Assuming this input XML

<?xml version="1.0" encoding="UTF-8"?>
<rows>
    <row>
        <cell>PART_ID</cell>
        <cell>TITLE</cell>
        <cell>ITEM_NUMBER</cell>
        <cell>SUBASSEMBLY_ITEM</cell>
        <cell>QUANTITY</cell>
    </row>
    <row>
        <cell>id1</cell>
        <cell> some title </cell>
        <cell>1</cell>
        <cell>y;x,z</cell>
        <cell>20</cell>
    </row>
    <row>
        <cell>id2</cell>
        <cell> another title </cell>
        <cell>2</cell>
        <cell>q/r|s</cell>
        <cell>10</cell>
    </row>
</rows>

here is a somewhat parametrised XPath-based solution to generically generate CSV output:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">
    
    <xsl:output method="text" encoding="UTF-8"/>
    
    
    <xsl:template match="/">
        <xsl:value-of select="
            let $escapeChar := '&quot;',
                $newLine    := '&#xA;',
                $separator  := ','
                return //row ! (string-join(* ! string-join($escapeChar||normalize-space(.)||$escapeChar),$separator),$newLine)"
            separator=""/>
    </xsl:template>

</xsl:stylesheet>

Output:

"PART_ID","TITLE","ITEM_NUMBER","SUBASSEMBLY_ITEM","QUANTITY" 
"id1","some title","1","y;x,z","20" 
"id2","another title","2","q/r|s","10" 

If you want a more XSLT-based solution I’d recommend to make use of templates:

<xsl:variable name="escapeChar" select="'&quot;'" as="xs:string"/>
<xsl:variable name="separator" select="','" as="xs:string"/>
<xsl:variable name="newLine" select="'&#xA;'" as="xs:string"/>

<!-- identity template or shallow-skip -->
<xsl:mode on-no-match="shallow-skip"/>

<xsl:template match="//row">
    <xsl:apply-templates select="*"/>
    <xsl:value-of select="$newLine"/>
</xsl:template>

<xsl:template match="*[parent::row]">
    <xsl:value-of select="$escapeChar"/>
    <xsl:value-of select="."/>
    <xsl:value-of select="$escapeChar"/>
    <xsl:if test="not(position()=last())">
        <xsl:value-of select="$separator"/>
    </xsl:if>
</xsl:template>

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top