title: CSV to XML using XSLT-1.0 group by first 0 value
body: <p>I would like to use the XSLT 1.0 engine to transform a CSV file to an XML document. The CSV file contains documents for each customer with a flexible amount of document lines. Each new document starts with 0.</p>
  <p><strong>CSV example:</strong></p>
  <pre><code>&lt;root&gt;
  0;15-01-2022;Customer1
  1;Dual monitors;50
  2;Laser mouse;10.50
  0;21-1-2022;Customer5
  1;Multi-jet printer;100
  0;30-1-2022;Customer8
  1;Goods returned;-200
  2;Basic keyboard;300
  &lt;/root&gt;
  </code></pre>
  <p>Here's the result <strong>XML document</strong> I would like to get:</p>
  <pre><code>&lt;Documents&gt;
     &lt;Document&gt;
        &lt;Header&gt;
           &lt;Customer&gt;Customer1&lt;/Customer&gt;
           &lt;Date&gt;15-01-2022&lt;/Date&gt;
        &lt;/Header&gt;
        &lt;Lines&gt;
           &lt;Line&gt;
              &lt;LineNumber&gt;1&lt;/LineNumber&gt;
              &lt;Price&gt;50&lt;/Price&gt;
              &lt;Description&gt;Dual monitors&lt;/Description&gt;
           &lt;/Line&gt;
           &lt;Line&gt;
              &lt;LineNumber&gt;2&lt;/LineNumber&gt;
              &lt;Price&gt;10.50&lt;/Price&gt;
              &lt;Description&gt;Laser mouse&lt;/Description&gt;
           &lt;/Line&gt;
        &lt;/Lines&gt;
     &lt;/Document&gt;
     &lt;Document&gt;
        &lt;Header&gt;
           &lt;Customer&gt;Customer5&lt;/Customer&gt;
           &lt;Date&gt;21-1-2022&lt;/Date&gt;
        &lt;/Header&gt;
        &lt;Lines&gt;
           &lt;Line&gt;
              &lt;LineNumber&gt;1&lt;/LineNumber&gt;
              &lt;Price&gt;100&lt;/Price&gt;
              &lt;Description&gt;Multi-jet printer&lt;/Description&gt;
           &lt;/Line&gt;
        &lt;/Lines&gt;
     &lt;/Document&gt;
     &lt;Document&gt;
        &lt;Header&gt;
           &lt;Customer&gt;Customer8&lt;/Customer&gt;
           &lt;Date&gt;30-1-2022&lt;/Date&gt;
        &lt;/Header&gt;
        &lt;Lines&gt;
           &lt;Line&gt;
              &lt;LineNumber&gt;1&lt;/LineNumber&gt;
              &lt;Price&gt;-200&lt;/Price&gt;
              &lt;Description&gt;Goods returned&lt;/Description&gt;
           &lt;/Line&gt;
           &lt;Line&gt;
              &lt;LineNumber&gt;2&lt;/LineNumber&gt;
              &lt;Price&gt;300&lt;/Price&gt;
              &lt;Description&gt;Basic keyboard&lt;/Description&gt;
           &lt;/Line&gt;
        &lt;/Lines&gt;
     &lt;/Document&gt;
  &lt;/Documents&gt;
  </code></pre>
  <p>I would like to group the document lines to the XML, but my problem is that I can’t find a working method in the for-each line section.</p>
  <p><strong>XSLT</strong> I tried:</p>
  <pre><code>&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:exsl=&quot;http://exslt.org/common&quot; extension-element-prefixes=&quot;exsl&quot;&gt;
      &lt;xsl:output method=&quot;xml&quot; version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; indent=&quot;yes&quot;/&gt;
      &lt;xsl:key name=&quot;k1&quot; match=&quot;row&quot; use=&quot;cell[1]&quot;/&gt;
      &lt;xsl:template match=&quot;/&quot;&gt;
          &lt;!-- tokenize csv --&gt;
          &lt;xsl:variable name=&quot;rows&quot;&gt;
              &lt;xsl:call-template name=&quot;tokenize&quot;&gt;
                  &lt;xsl:with-param name=&quot;text&quot; select=&quot;root&quot;/&gt;
              &lt;/xsl:call-template&gt;
          &lt;/xsl:variable&gt;
          &lt;xsl:variable name=&quot;data&quot;&gt;
              &lt;xsl:for-each select=&quot;exsl:node-set($rows)/row[position() &gt; 0]&quot;&gt;
                  &lt;row&gt;
                      &lt;xsl:call-template name=&quot;tokenize&quot;&gt;
                          &lt;xsl:with-param name=&quot;text&quot; select=&quot;.&quot;/&gt;
                          &lt;xsl:with-param name=&quot;delimiter&quot; select=&quot;';'&quot;/&gt;
                          &lt;xsl:with-param name=&quot;name&quot; select=&quot;'cell'&quot;/&gt;
                      &lt;/xsl:call-template&gt;
                  &lt;/row&gt;
              &lt;/xsl:for-each&gt;
          &lt;/xsl:variable&gt;
          &lt;!-- output --&gt;
          &lt;Documents&gt;
              &lt;xsl:for-each select=&quot;exsl:node-set($data)/row[cell[1] = 0]&quot;&gt;
                  &lt;Document&gt;
                      &lt;Header&gt;
                          &lt;Customer&gt;
                              &lt;xsl:value-of select=&quot;cell[3]&quot;/&gt;
                          &lt;/Customer&gt;
                          &lt;Date&gt;
                              &lt;xsl:value-of select=&quot;cell[2]&quot;/&gt;
                          &lt;/Date&gt;
                      &lt;/Header&gt;
                      &lt;Lines&gt;
                          &lt;xsl:for-each select=&quot;exsl:node-set($data)/row[cell[1] &gt; 0]&quot;&gt;
                              &lt;Line&gt;
                                  &lt;LineNumber&gt;
                                      &lt;xsl:value-of select=&quot;cell[1]&quot;/&gt;
                                  &lt;/LineNumber&gt;
                                  &lt;Price&gt;
                                      &lt;xsl:value-of select=&quot;cell[3]&quot;/&gt;
                                  &lt;/Price&gt;
                                  &lt;Description&gt;
                                      &lt;xsl:value-of select=&quot;cell[2]&quot;/&gt;
                                  &lt;/Description&gt;
                              &lt;/Line&gt;
                          &lt;/xsl:for-each&gt;
                      &lt;/Lines&gt;
                  &lt;/Document&gt;
              &lt;/xsl:for-each&gt;
          &lt;/Documents&gt;
      &lt;/xsl:template&gt;
      &lt;xsl:template name=&quot;tokenize&quot;&gt;
          &lt;xsl:param name=&quot;text&quot;/&gt;
          &lt;xsl:param name=&quot;delimiter&quot; select=&quot;'&amp;#10;'&quot;/&gt;
          &lt;xsl:param name=&quot;name&quot; select=&quot;'row'&quot;/&gt;
          &lt;xsl:variable name=&quot;token&quot; select=&quot;substring-before(concat($text, $delimiter), $delimiter)&quot;/&gt;
          &lt;xsl:if test=&quot;$token&quot;&gt;
              &lt;xsl:element name=&quot;{$name}&quot;&gt;
                  &lt;xsl:value-of select=&quot;$token&quot;/&gt;
              &lt;/xsl:element&gt;
          &lt;/xsl:if&gt;
          &lt;xsl:if test=&quot;contains($text, $delimiter)&quot;&gt;
              &lt;!-- recursive call --&gt;
              &lt;xsl:call-template name=&quot;tokenize&quot;&gt;
                  &lt;xsl:with-param name=&quot;text&quot; select=&quot;substring-after($text, $delimiter)&quot;/&gt;
                  &lt;xsl:with-param name=&quot;delimiter&quot; select=&quot;$delimiter&quot;/&gt;
                  &lt;xsl:with-param name=&quot;name&quot; select=&quot;$name&quot;/&gt;
              &lt;/xsl:call-template&gt;
          &lt;/xsl:if&gt;
      &lt;/xsl:template&gt;
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  <p>Unfortunately this template will not stop with the lines before the next &quot;0&quot; value. I don't need to sum the prices yet.
  If anyone has any ideas on how I could achieve this that would be greatly appreciated! Unfortunately I’m limited to the XSLT 1.0 version.</p>