need to merge xml nodes based on an attribute value
I need to merge certain xml nodes based on an attribute value, change that attribute value on the merged node and sum another attribute.
I am able to change the value of the attributes, but I couldn't figure out how to sum(@count) and assign it to @count on the resulting xml
Source xml
<xml>
<books category="X" count="2">
<book name="bookx1"/>
<book name="bookx2"/>
</books>
<books category="Y" count="3">
<book name="booky1"/>
<book name="booky2"/>
<book name="booky3"/>
</books>
<books category="Z" count="2">
<book name="bookz1"/>
<book name="bookz2"/>
</books></xml>
After xslt transform it needs to be like this
<xml>
<books category="A" count="5">
<book name="bookx1"/>
<book name="bookx2"/>
<book name="booky1"/>
<book name="booky2"/>
<book name="booky3"/>
</books>
<books category="Z" count="2">
<book name="bookz1"/>
<book name="bookz2"/>
</books></xml>
This is my partial xslt
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="@category">
<xsl:attribute name="category">
<xsl:choose>
<xsl:when test=".='X'">
<xsl:text>A</xsl:text>
</xsl:when>
<xsl:when test=".='Y'">
<xsl:text>A</xsl:text>
</xsl:when>
<xsl:when test=".='Z'">
<xsl:text>B</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
<xsl:template match="books[@category='X']"/>
开发者_如何学Python<xsl:template match="books[@category='Y']"/></xsl:transform>
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:strip-space elements="*"/>
<xsl:key name="kBooksByCat" match="books"
use="@category = 'Z'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xml>
<xsl:variable name="vNonZ"
select="key('kBooksByCat', 'false')"/>
<xsl:variable name="vCatZ"
select="key('kBooksByCat', 'true')"/>
<xsl:if test="$vNonZ">
<books category="A" count="{sum($vNonZ/@count)}">
<xsl:apply-templates select="$vNonZ/node()"/>
</books>
</xsl:if>
<xsl:if test="$vCatZ">
<books category="B" count="{sum($vCatZ/@count)}">
<xsl:apply-templates select="$vCatZ/node()"/>
</books>
</xsl:if>
</xml>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<xml>
<books category="X" count="2">
<book name="bookx1"/>
<book name="bookx2"/>
</books>
<books category="Y" count="3">
<book name="booky1"/>
<book name="booky2"/>
<book name="booky3"/>
</books>
<books category="Z" count="2">
<book name="bookz1"/>
<book name="bookz2"/>
</books>
</xml>
produces the wanted, correct result:
<xml>
<books category="A" count="5">
<book name="bookx1"/>
<book name="bookx2"/>
<book name="booky1"/>
<book name="booky2"/>
<book name="booky3"/>
</books>
<books category="B" count="2">
<book name="bookz1"/>
<book name="bookz2"/>
</books>
</xml>
Another stylesheet without key:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="books[@category='Z'][1]">
<xsl:variable name="us" select="../books[@category='Z']"/>
<books category="B" count="{sum($us/@count)}">
<xsl:apply-templates select="$us/node()"/>
</books>
</xsl:template>
<xsl:template match="books[@category!='Z'][1]">
<xsl:variable name="us" select="../books[@category!='Z']"/>
<books category="A" count="{sum($us/@count)}">
<xsl:apply-templates select="$us/node()"/>
</books>
</xsl:template>
<xsl:template match="books"/>
</xsl:stylesheet>
Output:
<xml>
<books category="A" count="5">
<book name="bookx1"></book>
<book name="bookx2"></book>
<book name="booky1"></book>
<book name="booky2"></book>
<book name="booky3"></book>
</books>
<books category="B" count="2">
<book name="bookz1"></book>
<book name="bookz2"></book>
</books>
</xml>
Note: Just for fun. The two books templates are so close. Maybe there is a way to express those in one template. Some complex translate
?
精彩评论