Reputation: 31
I am a newbie in XSLT, I have an XML converted from csv file looks like below with Open and Close rows distict by text, type rows and value. They all come in with same record tags, with distinction only in the string values itself
<?xml version="1.0" encoding="utf-8"?>
<Items>
<Row>
<Transaction>Open</Transaction>
</Row>
<Row>
<Transaction>Type plus</Transaction>
</Row>
<Row>
<Transaction>A</Transaction>
</Row>
<Row>
<Transaction>B</Transaction>
</Row>
<Row>
<Transaction>Close</Transaction>
</Row>
<Row>
<Transaction>Open</Transaction>
</Row>
<Row>
<Transaction>Type minus</Transaction>
</Row>
<Row>
<Transaction>C</Transaction>
</Row>
<Row>
<Transaction>D</Transaction>
</Row>
<Row>
<Transaction>Close</Transaction>
</Row>
...
...
...
...
...
</Items>
I want the result to look as the following.I tried using a variable to store the using variable "Type" for storing plus or minus, but seems like I can't update the variable. Can anyone create an xsl which can do the transformation to the following.
<?xml version="1.0" encoding="utf-8"?>
<result>
<message>
<to>plus</to>
<from>A</from>
</message>
<message>
<to>plus</to>
<from>B</from>
</message>
<message>
<to>minus</to>
<from>C</from>
</message>
<message>
<to>minus</to>
<from>D</from>
</message>
...
...
...
</result>
Upvotes: 0
Views: 718
Reputation: 116993
The example is rather ambiguous; what we need here is some clear rules.
If we assume that in each group of Row
s starting with <Transaction>Open</Transaction>
, the second Row
contains the type and the last one closes the group, we can do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="grp" match="Row[not(Transaction='Open')]" use="generate-id(preceding-sibling::Row[Transaction='Open'][1])" />
<xsl:template match="Items">
<result>
<xsl:for-each select="Row[Transaction='Open']">
<xsl:variable name="group" select="key('grp', generate-id())" />
<xsl:variable name="type" select="substring-after($group[1]/Transaction, 'Type ')" />
<xsl:for-each select="$group[position() != 1 and position() != last()]">
<message>
<to>
<xsl:value-of select="$type"/>
</to>
<from>
<xsl:value-of select="Transaction"/>
</from>
</message>
</xsl:for-each>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
to obtain:
<?xml version="1.0" encoding="UTF-8"?>
<result>
<message>
<to>plus</to>
<from>A</from>
</message>
<message>
<to>plus</to>
<from>B</from>
</message>
<message>
<to>minus</to>
<from>C</from>
</message>
<message>
<to>minus</to>
<from>D</from>
</message>
</result>
Upvotes: 1