tags:

views:

32

answers:

1

Hi all:

I have the following xml and want to insert additional xml into it:

<root>
    <steps>
        <step name="step1" type="process">
            <steps>
                <step name="substep1">
                </step>
            </steps>
        </step>
        <step name="step2" type="process">
            <steps>
                <step name="substep1">
                <!-- more substeps...-->
                </step>
            </steps>
        </step>
        <step name="step3" type="process">
            <steps>
                <step name="substep1">
                </step>
                <step name="substep2">
                </step>
                <!-- more substeps...-->
            </steps>
        </step>
        <!-- THE BELOW IS WHAT I WISH TO ADD... and it has to be here -->
        <step name="reference">
            <!-- These stuff have been hardcoded in my xsl so its fine -->
        </step>
        <!-- ends -->
    </steps>
    <references>
        <reference name="reference1">
        </reference>
        .
        .
        .
    </references>
</root>

As I've written in the xml sample, I wish to add an additional step element as the very last step within the outter most steps. I have the xml snippet already hardcoded in my xsl so all I needed to do is to find the best logic to move to that particular point of the xml tree so I can call the template and have that snipet added in.

What is the recommended/best approach to do this?

Thanks.

+2  A: 

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 exclude-result-prefixes="xsl">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pAddition">
   <step name="reference">
     <XXX/>
   </step>
 </xsl:param>

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

 <xsl:template match="/*/steps/step[position()=last()]">
  <xsl:call-template name="identity"/>
  <xsl:copy-of select="$pAddition"/>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<root>
    <steps>
        <step name="step1" type="process">
            <steps>
                <step name="substep1">
                </step>
            </steps>
        </step>
        <step name="step2" type="process">
            <steps>
                <step name="substep1">
                <!-- more substeps...-->
                </step>
            </steps>
        </step>
        <step name="step3" type="process">
            <steps>
                <step name="substep1">
                </step>
                <step name="substep2">
                </step>
                <!-- more substeps...-->
            </steps>
        </step>
    </steps>
    <references>
        <reference name="reference1">
        </reference>
        .
        .
        .
    </references>
</root>

produces the wanted, correct result:

<root>
   <steps>
      <step name="step1" type="process">
         <steps>
            <step name="substep1"/>
         </steps>
      </step>
      <step name="step2" type="process">
         <steps>
            <step name="substep1"><!-- more substeps...--></step>
         </steps>
      </step>
      <step name="step3" type="process">
         <steps>
            <step name="substep1"/>
            <step name="substep2"/><!-- more substeps...-->
         </steps>
      </step>
      <step name="reference">
         <XXX/>
      </step>
   </steps>
   <references>
      <reference name="reference1"/>
        .
        .
        .
    </references>
</root>

Do note:

  1. **The identity rule is used to copy all nodes as is.

  2. The XML fragment to be inserted is specified (for convenience) as the body of a global xsl:param. In a realistic application it will be in a separate xml file and will be obtained using the xslt document() function.

  3. The template that matches the insertion point copies the matched node by calling the identity rule. then it copies the content of the xsl:param and thus the new conted is output exactly at the desired insertion point.

Dimitre Novatchev
@Dimitre: +1 Good answer. That's the way I would do. But I think it would easier to just copy the param RTF.
Alejandro
@Alejandro: Hey, where is the +1 :) ? As for literal copying -- yes, but you and I both know well that we apply templates to achieve flexibility -- tomorrow someone may ask as to do some processing on the parameter contents, too.
Dimitre Novatchev
@Alejandro: Actually, you were right. I simplified a lot the transformation -- see the edits.
Dimitre Novatchev
@Dimitre: Ja! Sorry for the delay! I have so much work today...
Alejandro