1
votes

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?

2
How do you decide whether to output <group>ALL</group> or <group>First Group</group>? - Mathias Müller
Yea I should have been more clear. <group>All</group> is the default. What happening is that the node has to be duplicated for each group its in. Give me a second to modify my question to make it more clear. - ksrb
I have edited my answer accordingly (XSLT code and output), i.e. to work with your updated input. - Mathias Müller

2 Answers

2
votes

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

1
votes

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.