Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple XML Restructure with XSLT

Tags:

xml

xslt

I'm new to XSLT and I'm trying to achieve a reasonably simple restructure. I have an xml document representing a person (for illustrative purposes). I have numerous elements under person. From these I want to extract the first_name and last_name (and crucially others) into a new full_name element. I've seen the question here. The "renameWrapped" approach works. However it's not generic enough as I can't guarantee the ordering of the elements in the input document.

I have the following XML:

<?xml version="1.0" encoding="utf-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
    <myname:attr1>some value</myname:attr1>
    <myname:first_name>john</myname:first_name>
    <myname:last_name>smith</myname:last_name>
    <myname:attr2>some value</myname:attr2>
    <!-- other person stuff -->
</myname:Person>

This is transformed by the following xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:myname="http://www.myname.co.uk/def">
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="myname:Person">
        <myname:Person>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
            </xsl:copy>
            <myname:FullName>
                <xsl:apply-templates select="myname:first_name | myname:last_name"/>
            </myname:FullName>
        </myname:Person>
    </xsl:template>

</xsl:stylesheet>

However this is giving me the following output with myname:Person being duplicated:

<?xml version="1.0" encoding="UTF-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
    <myname:Person>
        <myname:attr1>some value</myname:attr1>
        <myname:attr2>some value</myname:attr2>
    </myname:Person>
    <myname:FullName>
        <myname:first_name>john</myname:first_name>
        <myname:last_name>smith</myname:last_name>
    </myname:FullName>
</myname:Person>

What am I doing wrong?

Thanks in advance for your help.

like image 645
Oliver Shaw Avatar asked May 06 '26 16:05

Oliver Shaw


1 Answers

One of the <myname:Person> elements comes from the literal result element in your template, the other comes from the <xsl:copy>. If you want

<?xml version="1.0" encoding="UTF-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
    <myname:attr1>some value</myname:attr1>
    <myname:attr2>some value</myname:attr2>
    <myname:FullName>
        <myname:first_name>john</myname:first_name>
        <myname:last_name>smith</myname:last_name>
    </myname:FullName>
</myname:Person>

then simply leave out the <xsl:copy>, i.e.

<xsl:template match="myname:Person">
    <myname:Person>
        <xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
        <myname:FullName>
            <xsl:apply-templates select="myname:first_name | myname:last_name"/>
        </myname:FullName>
    </myname:Person>
</xsl:template>

or alternatively leave out the explicit <myname:Person>:

<xsl:template match="myname:Person">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
        <myname:FullName>
            <xsl:apply-templates select="myname:first_name | myname:last_name"/>
        </myname:FullName>
    </xsl:copy>
</xsl:template>
like image 74
Ian Roberts Avatar answered May 09 '26 04:05

Ian Roberts



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!