xslt - Unnest parent nodes by child node -
in xml there items 0-n attributes , item should copied each attribute new item 1 attribute.
given xml this:
<?xml version="1.0" encoding="utf-8" ?> <items> <item> <name>a</name> <attributes> <attribute> <key>attribute1</key> <value>1</value> </attribute> </attributes> </item> <item> <name>b</name> </item> <item> <name>c</name> <attributes> <attribute> <key>attribute1</key> <value>5</value> </attribute> <attribute> <key>attribute2</key> <value>2</value> </attribute> <attribute> <key>attribute3</key> <value>1</value> </attribute> </attributes> </item> </items>
result should be:
<?xml version="1.0" encoding="utf-8" ?> <root> <item> <name>a</name> <attribute_key>attribute1</attribute_key> <attribute_value>1</attribute_value> </item> <item> <name>b</name> </item> <item> <name>c</name> <attribute_key>attribute1</attribute_key> <attribute_value>5</attribute_value> </item> <item> <name>c</name> <attribute_key>attribute2</attribute_key> <attribute_value>2</attribute_value> </item> <item> <name>c</name> <attribute_key>attribute3</attribute_key> <attribute_value>1</attribute_value> </item> </root>
what have s far:
<?xml version="1.0" encoding="utf-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="item"> <xsl:if test="not(attributes/attribute)"> <item> <xsl:apply-templates select="@* | node()"/> </item> </xsl:if> <xsl:for-each select="./attributes/attribute"> <xsl:copy-of select="ancestor::item"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
so, parent "item" node gets copied correctly how remove attributes attribute for-each , place attribute direct child of "item"?
instead of copying item
node in entirity, manually create new item
, copy children (apart attributes
)
<xsl:for-each select="attributes/attribute"> <item> <xsl:copy-of select="ancestor::item/*[not(self::attributes)]"/> <!-- process attributes here --> </item> </xsl:for-each>
processing attributes matter of processing children, , using xsl:element
create new ones
<xsl:for-each select="*"> <xsl:element name="attribute_{local-name()}"> <xsl:value-of select="." /> </xsl:element> </xsl:for-each>
try xslt
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:output method="xml" indent="yes" /> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="item"> <xsl:if test="not(attributes/attribute)"> <item> <xsl:apply-templates select="@* | node()"/> </item> </xsl:if> <xsl:for-each select="attributes/attribute"> <item> <xsl:copy-of select="ancestor::item/*[not(self::attributes)]"/> <xsl:for-each select="*"> <xsl:element name="attribute_{local-name()}"> <xsl:value-of select="." /> </xsl:element> </xsl:for-each> </item> </xsl:for-each> </xsl:template> </xsl:stylesheet>
or if wanted take more template-based approach, should work
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:output method="xml" indent="yes" /> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="item[attributes/attribute]"> <xsl:apply-templates select="attributes/attribute" /> </xsl:template> <xsl:template match="item"> <item> <xsl:apply-templates select="@* | node()"/> </item> </xsl:template> <xsl:template match="attribute"> <item> <xsl:copy-of select="ancestor::item/*[not(self::attributes)]"/> <xsl:apply-templates select="*" /> </item> </xsl:template> <xsl:template match="attribute/*"> <xsl:element name="attribute_{local-name()}"> <xsl:value-of select="." /> </xsl:element> </xsl:template> </xsl:stylesheet>
Comments
Post a Comment