Reputation: 77
I have some xml files like the following. They contain all different tree structures and some elements do have attributes.
<root>
<element n="A">
<element n="B">
<attribute a="1"/>
<attribute a="2"/>
</element>
<element n="C">
<element n="D">
<attribute a="3"/>
</element>
</element>
</element>
</root>
I want to transform these files using XSLT to get the following output. I have to keep the tree structure and also create a list of all elements with their attributes:
<root>
<structure>
<newElement n="A">
<newElement n="B">
<newAttribute a="1"/>
<newAttribute a="2"/>
</newElement>
<newElement n="C">
<newElement n="D">
<newAttribute a="3"/>
</newElement>
</newElement>
</newElement>
</structure>
<list>
<listElement n="A"/>
<listElement n="B">
<listAttribute a="1"/>
<listAttribute a="2"/>
</listElement>
<listElement n="C"/>
<listElement n="D">
<listAttribute a="3"/>
</listElement>
</list>
</root>
I try to run two different templates "e1" and "e2" for one node "element" but it doesn't work. It seems that the first template is ignored. So what do I have to change?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<root>
<structure>
<xsl:apply-templates name="e1"/>
</structure>
<list>
<xsl:apply-templates name="e2"/>
</list>
</root>
</xsl:template>
<xsl:template match="element" name="e1">
<newElement>
<xsl:attribute name="n">
<xsl:value-of select="@n"/>
</xsl:attribute>
<xsl:apply-templates name="a1"/>
<xsl:apply-templates name="e1"/>
</newElement>
</xsl:template>
<xsl:template match="attribute" name="a1">
<newAttribute>
<xsl:attribute name="a">
<xsl:value-of select="@a"/>
</xsl:attribute>
</newAttribute>
</xsl:template>
<xsl:template match="element" name="e2">
<listElement>
<xsl:attribute name="n">
<xsl:value-of select="@n"/>
</xsl:attribute>
<xsl:apply-templates name="a2"/>
</listElement>
<xsl:apply-templates select="element"/>
</xsl:template>
<xsl:template match="attribute" name="a2">
<listAttribute>
<xsl:attribute name="a">
<xsl:value-of select="@a"/>
</xsl:attribute>
</listAttribute>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 2763
Reputation: 70638
It is not valid to use the name
attribute on xsl:apply-templates
. I am guessing your XSLT processing is simply ignoring the name in this case and is just dong a simple <xsl:apply-templates />
.
I think what you need to use here is the mode
attribute. When you use the mode
attribute, it will only use matching templates with the same mode
, allowing you to have two templates that match the same element.
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<root>
<structure>
<xsl:apply-templates mode="e1"/>
</structure>
<list>
<xsl:apply-templates mode="e2"/>
</list>
</root>
</xsl:template>
<xsl:template match="element" mode="e1">
<newElement n="{@n}">
<xsl:apply-templates mode="e1"/>
</newElement>
</xsl:template>
<xsl:template match="attribute" mode="e1">
<newAttribute a="{@a}"/>
</xsl:template>
<xsl:template match="element" mode="e2">
<listElement n="{@n}">
<xsl:apply-templates select="attribute" mode="e2"/>
</listElement>
<xsl:apply-templates select="element" mode="e2"/>
</xsl:template>
<xsl:template match="attribute" mode="e2">
<listAttribute a="{@a}"/>
</xsl:template>
</xsl:stylesheet>
Note the use of "Attribute Value Templates" here, to simplify the XSLT.
Upvotes: 7