Datatool can do this task by looping over all items and inserting the desired \section, \subsection, and \begin{itemize}/\end{itemize} commands based on checking whether the values have changed. The basic algorithm is:
- If the Section value of the current row is different from the previous value, then close the previous
itemize (except when there was no previous subsection) and add a \section{current row value} command - If the Subsection value of the current row is different from the previous value, then:
- add an
\end{itemize} command to end the list from the previous subsection (except when it is the first subsection in a section) - add a
\subsection{current row value} command - add a
\begin{itemize} command
- Add a line
\item[item label] item contents
For this you need to know what the previous section and subsection are, which you can store in separate commands for comparison. These commands should be adjusted to store the new value in order to compare them for the next line.
Implementation of this algorithm with datatool:
\documentclass{article} \ExplSyntaxOn \cs_new_eq:NN \strcompare \str_if_eq:eeTF \ExplSyntaxOff \usepackage{datatool} \DTLloadrawdb{items}{myitems.csv} \dtlsort{Section,Subsection,itemnumber}{items}{\dtlcompare} % sort the csv (might not be needed if it is already in the desired order) \begin{document} \def\currsection{-1} % separate commands for comparison \def\currsubsection{-1} % \DTLforeach{items}{% \mysection=Section,\mysubsection=Subsection,\itemlabel=itemnumber,\itemcontents=text}{% \strcompare{\mysection}{\currsection}{}{% csv goes to a new section \strcompare{\currsubsection}{-1}{}{% check if there is a previous subsection with itemize that needs to be closed first \end{itemize} } \edef\currsection{\mysection}% update current section value for comparison in the next row \def\currsubsection{-1}% reset current subsection value to force a new \begin{itemize} in the check below \section{\mysection}% start the new section } \strcompare{\mysubsection}{\currsubsection}{% check for a new subsection \item[\itemlabel] \itemcontents}{% subsection still the same, only add an \item \strcompare{\currsubsection}{-1}{}{% subsection different, if it was not the first in the section then close previous itemize \end{itemize} } \edef\currsubsection{\mysubsection}% update current subsection value for comparison in the next row \subsection{\mysubsection}% start the new subsection \begin{itemize} % with an itemize \item[\itemlabel] \itemcontents % and the item }% } \end{itemize} % close the final itemize after the csv file is finished \end{document}
Result:

Note that here the command \DTLloadrawdb is used instead of the regular \DTLloaddb. This is done because the csv contained underscore (_) characters. This also means that you cannot use any LaTeX code in the csv. If you want this then use DTLloaddb and avoid underscores in text.
Relatedly, the column headers cannot contain underscores at all, so I changed item_number in the csv to itemnumber.
Note also that the code above sorts the csv first by Section, then Subsection, then itemnumber. This may not be needed or desired, and it can also be slow for larger files, so it may be better to remove the line performing the sort and sorting the data first before loading it into datatool.
Without the sorting line the output would be:

\documentclass{...}, the required\usepackage's,\begin{document}, and\end{document}. That may seem tedious to you, but think of the extra work it represents for the users willing to give you a hand. Help them help you: remove that one hurdle between you and a solution to your problem.datatoolandcsvsimpleshould be interesting for you.