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.
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">
<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">
<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.
精彩评论