简体   繁体   中英

Renaming all child nodes of an XML node using XSLT

I have an XML file with the following structure.

<Telefon>
    <area>0123</area>
    <number>456</number>
    <extension>789</extension>
</Telefon>
<Fax>
    <area>3210</area>
    <number>654</number>
    <extension>1098</extension>
</Fax>

I would like to transform this using XSLT to the following

<telefon-area>0123</area>
<telefon-number>456</number>
<telefon-extension>789</extension>
<fax-area>3210</area>
<fax-number>654</number>
<fax-extension>1098</extension>

I got so far as using the copy template, and while I could write templates to manually change these fields, I would like to only writes one adding the telefon- or fax- prefix to each child nodes of the previous Telefon and Fax nodes.

This is the structure I come up with so far:

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

<!--The next template removes the telefon tag but I do not know how to modify the child nodes to extend them with the telefon- prefix.-->
<xsl:template match="Telefon">
    <xsl:apply-templates select="@*|node()"/> 
</xsl:template>

Thank you for your help!

To match the children of the Telefon node, you could do this...

<xsl:template match="Telefon/*">

And you could extend it like this, to handle Fax too

 <xsl:template match="Telefon/*|Fax/*">

Within this, you could use xsl:element together with local-name() to create a new element name.

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" />

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

    <!--The next template removes the telefon tag but I do not know how to modify the child nodes to extend them with the telefon- prefix.-->
    <xsl:template match="Telefon|Fax">
        <xsl:apply-templates /> 
    </xsl:template>

    <xsl:template match="Telefon/*|Fax/*">
        <xsl:element name="{local-name(..)}-{local-name()}">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Note, in the template matching Telefon , you only really need do <xsl:apply-templates /> as you probably want to ignore any attributes on Telefon if there were any.

Alternatively, you could make use of a "mode", if you had other elements, in addition to Telefon and Fax you wanted to change too

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" />

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

    <!--The next template removes the telefon tag but I do not know how to modify the child nodes to extend them with the telefon- prefix.-->
    <xsl:template match="Telefon|Fax">
        <xsl:apply-templates mode="child" /> 
    </xsl:template>

    <xsl:template match="*" mode="child">
        <xsl:element name="{local-name(..)}-{local-name()}">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Note, this doesn't make the name all lower-case. If you wanted that, then it would depend if you were using XSLT 2.0 or XSLT 1.0.

Ideally, you can use XSLT 2.0, and do this...

 <xsl:element name="{lower-case(local-name(..))}-{local-name()}">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM