xmlxsltxslt-1.0xslt-2.0

XML to CSV for child nodes


With below XSLT code able to convert from XML to CSV with enclosed quotes, but the child node (Details) is appearing in the same line.

Update: As mentioned in the forum I have updated the question with expected output.

XML Input

<?xml version="1.0" encoding="UTF-8"?>
 <Root>
  <Records>
    <TrRecords>
      <RecordID>0123</RecordID>
      <SequnceNumber>00001</SequnceNumber>
      <TNumber>00001</TNumber>
      <System>01</System>
      <Amount>4956.00</Amount>
     <Reference>T</Reference>
     <Account>89768</Account>
     <Name>bdi</Name>
    <Other2/>
    <Other3/>
    <Details>
   <RecordID>1234</RecordID>
  <SequnceNumber>00001</SequnceNumber>
   <TNumber>00001</TNumber>
  <Number>TI</Number>
<InvoiceDate>2024-05-05</InvoiceDate>
 <InvoiceDescription/>
 <InvoiceAmount>10.00</InvoiceAmount>
 </Details>
  <Details>
   <RecordID>1234</RecordID>
  <SequnceNumber>00002</SequnceNumber>
   <TNumber>00001</TNumber>
  <Number>TI3</Number>
<InvoiceDate>2024-05-05</InvoiceDate>
 <InvoiceDescription/>
 <InvoiceAmount>10.00</InvoiceAmount>
 </Details>
</TrRecords>
 <TrRecords>
 <RecordID>0123</RecordID>
 <SequnceNumber>00001</SequnceNumber>
 <TNumber>00002</TNumber>
 <System>01</System>
 <Amount>523.00</Amount>
 <Reference>TI</Reference>
 <Account>18907</Account>
<Name>elci</Name>
 <Other2/>
 <Other3/>
 <Details>
 <RecordID>1234</RecordID>
<SequnceNumber>00001</SequnceNumber>
 <TNumber>00001</TNumber>
  <Number>TIR</Number>
 <InvoiceDate>2024-08-17</InvoiceDate>
 <InvoiceDescription/>
 <InvoiceAmount>5245.00</InvoiceAmount>
   </Details>
  </TrRecords>
   <TrRecords>
    <RecordID>0123</RecordID>
   <Number>00001</Number>
   <TNumber>00003</TNumber>
    <System>01</System>
   <Amount>1180.00</Amount>
  <Reference>EMI</Reference>
<AccountNo>0936201002941</AccountNo>
   <Other2/>
    <Other3/>
 <Details>
  <RecordID>1234</RecordID>
  <SequnceNumber>00001</SequnceNumber>
   <TNumber>00001</TNumber>
   <Number>Tac</Number>
   <InvoiceDate>2024-08-17</InvoiceDate>
   <InvoiceDescription/>
    <InvoiceAmount>1180.00</InvoiceAmount>
     </Details>
  </TrRecords>
   </Records>
   </Root>

XSLT code

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="utf-8" />
  <xsl:param name="delim" select="','" />
  <xsl:param name="quote" select="'&quot;'" />
   <xsl:param name="break" select="'&#xA;'" />
  <xsl:template match="/Root">
   <xsl:apply-templates select="Records/TrRecords" />
   </xsl:template>
  <xsl:template match="TrRecords">
   <xsl:apply-templates />
   <xsl:if test="following-sibling::*">
    <xsl:value-of select="$break" />
    </xsl:if>
  <xsl:for-each select="Details">
  <xsl:if test="following-sibling::*">
  <xsl:value-of select="$break" />
   </xsl:if>
 </xsl:for-each>
 </xsl:template>
 <xsl:template match="*">
<!-- remove normalize-space()  --> 
   <xsl:value-of select="concat($quote, normalize-space(), $quote)" />
  <xsl:if test="following-sibling::*">
  <xsl:value-of select="$delim" />
   </xsl:if>
   </xsl:template>
  <xsl:template match="text()" />
  </xsl:stylesheet>

Expected output

"0123","00001","00001","01","4956.00","T","89768","bdi","",""
"1234","00001","00001","TI","2024-05-05","","10.00"
"1234","00002","00001","TI3","2024-05-05","","10.00"
"0123","00001","00002","01","523.00","TI","18907","elci","",""
"1234","00001","00001","TIR","2024-08-17","","5245.00"
"0123","00001","00003","01","1180.00","EMI","0936201002941","",""
"1234","00001","00001","Tac","2024-08-17","","1180.00"

In each line from 1234 the values should come in new line with enclosed quotes. could you please help me with this.

Regards, Janardhan


Solution

  • (modified)

    Try something like:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="utf-8" />
    <xsl:strip-space elements="*"/>
      
    <xsl:param name="delim" select="','" />
    <xsl:param name="quote" select="'&quot;'" />
    <xsl:param name="break" select="'&#xA;'" />
       
    <xsl:template match="/Root">
        <xsl:apply-templates select="Records/TrRecords" />
    </xsl:template>
       
    <xsl:template match="TrRecords">
        <xsl:apply-templates select="* except Details"/>
        <xsl:apply-templates select="Details"/>
        <xsl:if test="position()!=last()">
            <xsl:value-of select="$break" />
        </xsl:if>
    </xsl:template>
     
    <xsl:template match="Details">
        <xsl:value-of select="$break" />
        <xsl:apply-templates/>
     </xsl:template>
     
    <xsl:template match="*">
        <xsl:value-of select="concat($quote, normalize-space(), $quote)" />
        <xsl:if test="position()!=last()">
            <xsl:value-of select="$delim" />
        </xsl:if>
    </xsl:template>
       
    </xsl:stylesheet>
    

    Demo here.

    Note that this assumes none of the values passed to the output contains a quote.