4

I want to do something simple (or so I thought) using XSLT. I want to split a list of elements to two, rename an element using The idea is that a xml formed like this:

<elem at="value" id="something"/>
<elem at="value" id="something2"/>
<elem at="random" id="something3"/>

will be converted to:

<elemVal id="something"/>
<elemVal id="something2"/>
<elemRa id="something3"/>

(the new element names are static) So the elements are renamed based on the value of an attribute.

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
</xsl:template>

<xsl:template match="elem/@at[.='value']">
    <xsl:element name="elemVa">
        <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
</xsl:template>

So far I have an identity template, but I don't understand how I can go backwards and change the elements name, keeping it's content.

1 Answer 1

5

Instead of

<xsl:template match="elem/@at[.='value']">

you need

<xsl:template match="elem[@at ='value']">

then create the new element (a literal suffices) and make sure the at attribute is not processed:

<xsl:template match="elem[@at ='value']">
    <elemVa>
        <xsl:apply-templates select="@* except @at | node()"/>
    </elemVa>
</xsl:template>

The above is XSLT/XPath 2.0, in 1.0 you can use

<xsl:template match="elem[@at ='value']">
    <elemVa>
        <xsl:apply-templates select="@*[not(local-name() = 'at')] | node()"/>
    </elemVa>
</xsl:template>
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you! Could you perhaps explain the difference between the 2 match?
You want to transform the element, therefore the right approach is to match on the element (with a predicate describing the attribute condition). Your attempt matches on the attribute node, that does not enable you to transform the element.
OK. then one thing is missing, the removal of the attribute that I match upon.
My suggestion <xsl:apply-templates select="@* except @at | node()"/> respectively <xsl:apply-templates select="@*[not(local-name() = 'at')] | node()"/> would make sure the attribute is not processed further. Or write a template <xsl:template match="elem/@at"/> respectively <xsl:template match="elem/@at[. = ('value', 'random')]"/>.
With XSLT 2.0 you should be able to use @* except @xsi:type, assuming you have the namespace prefix xsi declared in your XSLT stylesheet. With XSLT 1.0 you can select @*[not(name() = 'xsi:type')]. It might indeed be better to write an empty template along the lines of <xsl:template match="elem/@xsi:type"/> or <xsl:template match="elem/@xsi:type[. = 'foo' or . = 'bar']"/>.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.