Reputation: 4283
There are examples to group items using xsl:key, but those don't work for my scenario.
Each set with column1="H" should be named <transaction>
, and all the items with column1="D" following the "H" should be inside the <transaction>
as <item>
, until it reaches the next "H". Then it repeats with the same rule.
Problem: The values are enclosed in double quotes, but the output shouldn't have double quotes.
<root>
<row>
<column1>"H"</column1>
<column2>"2016-09-09"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Conference Services Meeting Package"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Audio Visual Meeting Package"</column2>
</row>
<row>
<column1>"H"</column1>
<column2>"2016-09-09"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Meeting Package Lunch"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Marinated Roasted Olives</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Mezza Plate Humus with Smoked Paprika Butter"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Pastry Bread Block Loaf Bread"</column2>
</row>
</root>
Output:
<xml>
<transaction>
<item>Conference Services Meeting Package</item>
<item>Audio Visual Meeting Package</item>
</transaction>
<transaction>
<item>Meeting Package Lunch</item>
<item>Marinated Roasted Olives</item>
<item>Mezza Plate Humus with Smoked Paprika Butter</item>
<item>Pastry Bread Block Loaf Bread</item>
</transaction>
</xml>
Upvotes: 1
Views: 229
Reputation: 243459
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kFollowing" match='row[column1='"D"']'
use='generate-id(preceding-sibling::row[column1='"H"'][1])'/>
<xsl:template match="/*">
<xml>
<xsl:apply-templates select='row[column1='"H"']'/>
</xml>
</xsl:template>
<xsl:template match="row">
<transaction>
<xsl:apply-templates select="key('kFollowing', generate-id())/column2"/>
</transaction>
</xsl:template>
<xsl:template match="column2">
<item><xsl:value-of select=
'concat(translate(substring(.,1,1),'"',""),
substring(.,2, string-length(.) -2),
translate(substring(.,string-length()),'"',""))'/></item>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<row>
<column1>"H"</column1>
<column2>"2016-09-09"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Conference Services Meeting Package"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Audio Visual Meeting Package"</column2>
</row>
<row>
<column1>"H"</column1>
<column2>"2016-09-09"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Meeting Package Lunch"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Marinated Roasted Olives</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Mezza Plate Humus with Smoked Paprika Butter"</column2>
</row>
<row>
<column1>"D"</column1>
<column2>"Pastry Bread Block Loaf Bread"</column2>
</row>
</root>
produces exactly the wanted, correct result:
<xml>
<transaction>
<item>Conference Services Meeting Package</item>
<item>Audio Visual Meeting Package</item>
</transaction>
<transaction>
<item>Meeting Package Lunch</item>
<item>Marinated Roasted Olives</item>
<item>Mezza Plate Humus with Smoked Paprika Butter</item>
<item>Pastry Bread Block Loaf Bread</item>
</transaction>
</xml>
Explanation:
A key that defines all corresponding "D"
<column2>
elements as a function of the generate-id()
of their corresponding (nearest preceding) "H"
<column1>
element.
Translating the 1st and last characters from (only if they are a quote) "
to the empty string. Thus "Marinated Roasted Olives
is processed correctly, even though it doesn't end with a quote -- which most probably is accidental mistake.
No <xsl:for-each>
(even nested!) instruction.
Upvotes: 3
Reputation: 116959
Try it this way:
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:key name="tx" match="row[column1='"D"']" use="generate-id(preceding-sibling::row[column1='"H"'][1])" />
<xsl:template match="/root">
<xml>
<xsl:for-each select="row[column1='"H"']">
<transaction>
<xsl:for-each select="key('tx', generate-id())">
<item>
<xsl:value-of select="column2"/>
</item>
</xsl:for-each>
</transaction>
</xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>
This solves the problem of grouping adjacent items. The problem of removing the double quotes is rather trivial, and can be solved easily by using the substring()
function. Post a separate question if you can't make it work.
Upvotes: 2