Re: [xsl] Split one line to multiple lines

Subject: Re: [xsl] Split one line to multiple lines
From: "Graydon graydon@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 9 Oct 2014 20:22:46 -0000
On Thu, Oct 09, 2014 at 07:59:09PM -0000, sudheshna iyer sudheshnaiyer@xxxxxxxxx scripsit:
> I want to split the values in "Product" to multiple lines. For eg: for LineId = 222, there are 3 values (BBB;CCC;DDD;). So I need to create 3 lines along with the first line. How can I do that?
> Eg: 
> <ns1:Lines>
> <ns1:Line>
> <ns1:LineId>111</ns1:LineId>
> <ns1:Product>AA</ns1:Product>
> <ns1:Amount>100</ns1:Amount>
> </ns1:Line>
> <ns1:Line>
> <ns1:LineId>222</ns1:LineId>
> <ns1:Product>BBB;CCC;DDD;</ns1:Product>
> <ns1:Amount>200</ns1:Amount>
> </ns1:Line>
> </ns1:Lines>
> 
> Output
> <ns1:Lines>
> <ns1:Line>
> <ns1:LineId>111</ns1:LineId>
> <ns1:Product>AAA</ns1:Product>
> <ns1:Amount>100</ns1:Amount>
> </ns1:Line>
> <ns1:Line>
> <ns1:LineId>222</ns1:LineId>
> <ns1:Product>BBB</ns1:Product>
> <ns1:Amount>100</ns1:Amount>
> </ns1:Line>
> <ns1:Line>
> <ns1:LineId>222</ns1:LineId>
> <ns1:Product>CCC</ns1:Product>
> <ns1:Amount>100</ns1:Amount>
> </ns1:Line>
> <ns1:Line>
> <ns1:LineId>222</ns1:LineId>
> <ns1:Product>DDD</ns1:Product>
> <ns1:Amount>100</ns1:Amount>
> </ns1:Line>
> </ns1:Lines>
> 
> I know there is a tokenize function. But how do I copy other values?

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
</xsl:template>

<xsl:template match="ns1:Line">
    <xsl:variable name="original" select="." />
    <xsl:for-each select="tokenize(normalize-space(ns1:Product),';\p{Zs}*')[normalize-space()]">
        <ns1:Line>
            <xsl:apply-templates select="$original/ns1:LineId" />
            <ns1:Product>
                <xsl:value-of select="." />
            </ns1:Product>
            <xsl:apply-templates select="$original/ns1:Amount" />
        </ns1:Line>
    </xsl:for-each>
</xsl:template>


You notice that what you're doing is relative to the ns1:Line elements, and
that while you could select only those ns1:Line elements were you need to split
things

<xsl:template match="ns1:Line[matches(ns1:Product,';')]">

you don't need to; tokenizing where there aren't any semi-colons just returns
whatever was there.

You watch out for the trailing semi-colons by excluding the null string from
the sequence produced by tokenize -- that's what [normalize-space()] does --
and you use a variable to hang on to the original element context, which you
lose inside the for-each.

-- Graydon

Current Thread