tags:

views:

47

answers:

1

Hi All,

I am using XSLT to recurse some XML and then apply some HTML to the output. It will recurse the data, but it duplicates the parent item description and I am not sure why? I am sure it is right in front of my face, but I don't see it. It is inserting right after the <ul> tag when it goes to the next level in the XML.

XML Example:

<root>
    <filters>
        <filter ID="My Test">
            <item id="1">
                <description>MyTest Descrip</description>
                <item id="1">
                    <description>Sub Level - 1</description>
                </item>
                <item id="2">
                    <description>Sub Level - 2</description>
                </item>
                <item id="3">
                    <description>Sub Level - 3</description>
                <item id="4">
                <description>Sub Level 2 - 1</description>
                </item>
                    <item id="5">
                    <description>Sub Level 2 - 2</description>
                    </item>
                </item>
            </item>
        </filter>
    </filters>
</root>

XSLT Example:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="filter">
    <xsl:variable name="dataID" select="@ID"/>
        <ul class="searchdata">
            <xsl:apply-templates select="item"/>
        </ul>
    </xsl:template>
    <xsl:template match="item">
    <li>
        <xsl:variable name="searchID" select="@id"/>
        <input id="{$searchID}" type="checkbox"/>
        <label for="{$searchID}">
            <xsl:value-of select="description"/>
        </label>
        <xsl:if test="item">
        <ul>
            <xsl:apply-templates />
        </ul>
        </xsl:if>
    </li>
</xsl:template>
</xsl:stylesheet>

HTML Output:

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

    <ul class="searchdata"><li><input id="1" type="checkbox" /><label for="1">MyTest Descrip</label><ul>
    MyTest Descrip
     <li><input id="1" type="checkbox" /><label for="1">Sub Level - 1</label></li>
     <li><input id="2" type="checkbox" /><label for="2">Sub Level - 2</label></li>
          <li><input id="3" type="checkbox" /><label for="3">Sub Level - 3</label><ul>
              Sub Level - 3
              <li><input id="4" type="checkbox" /><label for="4">Sub Level 2 - 1</label></li>

              <li><input id="5" type="checkbox" /><label for="5">Sub Level 2 - 2</label></li>
          </ul></li>
     </ul></li></ul>

Any suggestions would be greatly appreciated.

Thanks.

+2  A: 

The problem is that you are not taking note about built-in rules, built-in rules for text node and elements in particular.

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

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

So, you need to add this strip-text-nodes rule:

<xsl:template match="text()"/>

And then your output will be:

<ul class="searchdata">
    <li>
        <input id="1" type="checkbox" />
        <label for="1">MyTest Descrip</label>
        <ul>
            <li>
                <input id="1" type="checkbox" />
                <label for="1">Sub Level - 1</label>
            </li>
            <li>
                <input id="2" type="checkbox" />
                <label for="2">Sub Level - 2</label>
            </li>
            <li>
                <input id="3" type="checkbox" />
                <label for="3">Sub Level - 3</label>
                <ul>
                    <li>
                        <input id="4" type="checkbox" />
                        <label for="4">Sub Level 2 - 1</label>
                    </li>
                    <li>
                        <input id="5" type="checkbox" />
                        <label for="5">Sub Level 2 - 2</label>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

Also, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="item"/>
    <xsl:template match="item[1]">
        <ul class="searchdata">
            <xsl:apply-templates select="../item" mode="li"/>
        </ul>
    </xsl:template>
    <xsl:template match="item" mode="li">
        <li>
            <input id="{@id}" type="checkbox"/>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
    <xsl:template match="description">
        <label for="{../@id}">
            <xsl:value-of select="."/>
        </label>
    </xsl:template>
</xsl:stylesheet>

Note: This has a rule matching description element explicitly, wich has more priority than built-in template rule for elements (apply templates to child nodes).

And last, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="node()">
        <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="item[1]">
        <ul class="searchdata">
            <xsl:call-template name="item"/>
        </ul>
    </xsl:template>
    <xsl:template match="item" name="item">
        <li>
            <input id="{@id}" type="checkbox"/>
            <xsl:apply-templates select="node()[1]"/>
        </li>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="description">
        <label for="{../@id}">
            <xsl:value-of select="."/>
        </label>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

Note: This use sequencial ("most fine grained traversal") instead of recursive template applying.

Alejandro
Alejandro....not sure I understand what you mean? Thanks for responding.
scarpacci
@Alejandro: +1 for offering several solutions, explaining the built-in templates and fine-grained traversal.
Dimitre Novatchev
Thanks a lot Alejandro....works great.
scarpacci
@scarpacci: You are wellcome!
Alejandro