tags:

views:

59

answers:

2

I have an XML organized like below-

<section name="Parent 1 Text here" ID="1" >
  <section name="Child 1 Text here" ID="11">
  </section>
  <section name="Child 2 Text here" ID="12">
    <section name="GrandChild Text here"  ID="121" >
    </section>
  </section>
</section>

<section name="Parent 2 Text here" ID="2" >
  <section name="Child 1 Text here" ID="22">
  </section>
  <section name="Child 2 Text here" ID="23">
    <section name="GrandChild Text here"  ID="232" >
    </section>
  </section>
</section>         

I have to produce the below output XML -

<section name="Parent 1 Text here" ID="1" >
  <section name="Child 2 Text here" ID="12">
    <section name="GrandChild Text here"  ID="121" >
    </section>
  </section>
</section>

<section name="Parent 2 Text here" ID="2" >
  <section name="Child 2 Text here" ID="23">
  </section>
</section>

I have to achive above using XSLT 1.0 transformation. I was planning to pass a comma separated string as a parameter with value= "1,12,121,2,23"

My question- How to loop the comma separated parameter in XSLT 1.0 ? Is there a simpler way to achieve the above. Please remember I have to do this in XSLT 1.0 Your help is appreciated.

+2  A: 

Recursion is not necessarily the solution. Basically your comma-seperated string can be applied as a filter:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:param name="filter">1,12,121,2,23</xsl:param>

  <xsl:template match="section">
    <xsl:if test="contains(concat(',', $filter, ','), concat(',', @ID, ','))">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

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

</xsl:stylesheet>
Jan Willem B
Thkx for ur solution.Above XML is- <?xml version="1.0" encoding="utf-8"?><document><documentinfo> <FirstName>Bob Graham</FirstName> <vehicle> <model year="2000" name="Intrigue" /> </vehicle> </documentinfo><documentbody> <section name="Parent 1 Text here" ID="1" > <section name="Child 1 Text here" ID="11"></section><section name="Child 2 Text here" ID="12"><section name="GrandChild Text here" ID="121" ></section></section></section></documentbody></document>How can I include the information inside <documentinfo> tag in the expression you have provided?
contactkx
I don't understand the question.
Jan Willem B
In the original XML i also need to show header info. The XML I gave earlier now looks like-<document><documentinfo><FirstName>Bob Graham</FirstName><vehicle><model year="2000" name="Intrigue" /></vehicle> </documentinfo><documentbody> <section name="Parent 1 Text here" ID="1" ><section name="Child here" ID="11"></section> <section name="GrandChild Text here" ID="121" ></section></section></section> </documentbody></document> Please paste above XML in notepad for clarity.My query is How to show FirstName,vehicle data in the final output XML,using the XSLT you have provided?
contactkx
Hi Jan, Please let me know if you have understood my question?
contactkx
With the XSLT, the documentinfo + subnodes are copied to the output XML. How is that different from what you ask?
Jan Willem B
A: 

Here is an alternative to Jan Willem B's approach. I don't claim that it is either better or worse. I present it for two reasons:

  1. You may want to see what a recursive approach would look like

  2. It behaves differently for some input data (although it behaves the same for your example data). Specifically, if your filter includes two nodes that are both descendants of the same node, this stylesheet will output two nested data structures, each with one leaf node, while Jan Willem B's answer outputs one nested structure with two leaf nodes. Don't know which you want.

For my stylesheet, you would pass a filter listing only the leaf nodes that you want. It will find the ancestors. I have assumed for this that your root node is called <doc>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml"/>

    <xsl:param name="descendant-ids" select="'121,23'"/>

    <xsl:template match="/">
        <doc>
            <xsl:call-template name="recurse-ids">
                <xsl:with-param name="ids" select="concat($descendant-ids,',')"/>
            </xsl:call-template>
        </doc>
    </xsl:template>

    <xsl:template name="recurse-ids">
        <xsl:param name="ids"/>
        <xsl:variable name="id" select="substring-before($ids,',')"/>
        <xsl:variable name="remaining-ids" select="substring-after($ids,',')"/>
        <xsl:apply-templates select="/doc/section">
            <xsl:with-param name="id" select="$id"/>
        </xsl:apply-templates>
        <xsl:if test="$remaining-ids">
            <xsl:call-template name="recurse-ids">
                <xsl:with-param name="ids" select="$remaining-ids"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="section">
        <xsl:param name="id"/>
        <xsl:if test="starts-with($id,@ID)">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()">
                    <xsl:with-param name="id" select="$id"/>
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

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