ksrb
ksrb

Reputation: 1945

XSLT add parent node name as element in child node

Input

<root>
    <category1>
        <node>
            <subnode>value</subnode>
        </node>
    </category1>

    <category2>
        <node>
            <subnode>value</subnode>
        </node>
    </category2>
</root>

Output

<root>
    <node>
        <subnode>value</subnode>
        </category1>
    </node>

    <node>
        <subnode>value</subnode>
        </category2>
    </node>
</root>

Or

<root>
    <node>
        <subnode>value</subnode>
        <status>category1</status>
    </node>

    <node>
        <subnode>value</subnode>
        <status>category2</status>
    </node>
</root>

Attempt

<xsl:template match="//node">
    <xsl:copy>
        <xsl:copy-of select="child::node()" />
        <xsl:copy-of select=".." />
        <!--
        Why isn't something like this possible? 
        <xsl:copy-of select="ancestor::local-name()"/> 
        -->
    </xsl:copy>
</xsl:template>

Details

Hopefully, the above was clear enough :).



Additional Details (Optional)

For those feeling especially generous this Christmas I invite you to continue reading :D.

I'm having some trouble learning XSLT and feel like I'm missing some general/syntactical concepts but I also need to do some 'complicated' transforms. For example:

Input

<root>
    <category1>
        <node>
            <name>category1 node pk</name>
        </node>
    </category1>

    <groups>
        <node>
            <name>First Group</name>
            <members>
                <name>category1 node pk</name>
            </members>
        </node>

        <node>
            <name>Second Group</name>
            <members>
                <name>category1 node pk</name>
            </members>
        </node>
    </groups>
</root>

Output

<root>
    <node>
        <name>category1 node pk</name>
        <group>All</group>
        <status>category1</status>
    </node>

    <node>
        <name>category1 node pk</name>
        <group>First Group</group>
        <status>category1</status>
    </node>

    <node>
        <name>category1 node pk</name>
        <group>Second Group</group>
        <status>category1</status>
    </node>
</root>

So for the XSLT experts out there what I would like to know is how you went about learning XSLT 1.0? Especially to deal with more complicated transforms.

Are there any books or tutorials that you found especially useful?

Finally how long do you think it would take for someone new to become proficient enough to pull off the above transform w/o help?

Upvotes: 1

Views: 1437

Answers (2)

Dave
Dave

Reputation: 56

the syntax for <xsl:copy-of select="ancestor::local-name()"/> is <xsl:value-of select="name(..)"/>. Slotting that in the full code is below

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="root">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="root/*">
    <xsl:apply-templates/>
</xsl:template>
<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="*"/>
        <status><xsl:value-of select="name(..)"/></status>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

and gives you the output

<?xml version="1.0" encoding="UTF-8"?>
<root>
<node>
    <subnode>value</subnode>
    <status>category1</status>
</node>
<node>
    <subnode>value</subnode>
    <status>category2</status>
</node>
</root>

as required

Upvotes: 2

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22647

This should help you to get started. I am aware that your actual XML input is more complex than that, but this produces exactly the output you describe (for the look-at-this-if-you-are-feeling-generous part).

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="root">
  <xsl:copy>
     <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="category1">
  <node>
     <name>
        <xsl:value-of select="node/name"/>
     </name>
     <group>
        <xsl:text>ALL</xsl:text>
     </group>
     <status>
        <xsl:text>category1</xsl:text>
     </status>
  </node>
</xsl:template>

<xsl:template match="groups">
  <xsl:for-each select="node">
     <node>
        <name>
           <xsl:value-of select="members/name"/>
        </name>
        <group>
           <xsl:value-of select="name"/>
        </group>
        <status>
           <xsl:text>category1</xsl:text>
        </status>
     </node>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

You get the following output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <node>
    <name>category1 node pk</name>
    <group>ALL</group>
    <status>category1</status>
 </node>

 <node>
    <name>category1 node pk</name>
    <group>First Group</group>
    <status>category1</status>
 </node>
 <node>
  <name>category1 node pk</name>
  <group>Second Group</group>
  <status>category1</status>
 </node>
</root>

Now, to your question about learning XSLT. If you meant books on the subject, Michael Kay's "Programmers Reference for XSLT 2.0 and XPATH" is by far the best resource if you do not mind technical details. See for example here: http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764569090.html.

Upvotes: 1

Related Questions