我的xml如下,
<doc>
<h1>main header 1-1</h1>
<p>para 1</p>
<p>para 2</p>
<h1>main header 1-2</h1>
<p>para 3</p>
<p>para 4</p>
<h2>sub header 2-1</h2>
<p>para 5</p>
<p>para 6</p>
<p>para 7</p>
<h2>sub header 2-3</h2>
<p>para 8</p>
<p>para 9</p>
<h1>main header 1-3</h1>
<p>para 10</p>
<h2>sub header 2-3</h2>
<p>para 11</p>
<p>para 12</p>
</doc>
我的要求是从<h1>
创建无序列表,如果<h2>
被放置为<h1>
的兄弟姐妹,则应列在<h1>
列表中。然后将这些列表项链接到<p>
个节点之后。
SO,我的预期输出,
<doc>
<div name="list">
<ul id="menu">
<li class='has-sub'><a href="h1-1">main header 1-1</a></li>
<li class='has-sub'><a href="h1-2">main header 1-2</a>
<ul>
<li class='last'><a href="h2-1">sub header 2-1</a></li>
<li class='last'><a href="h2-2">sub header 2-2</a></li>
</ul>
</li>
<li class='has-sub'><a href="h1-3">main header 1-3</a>
<ul>
<li class='last'><a href="h2-3">sub header 2-3</a></li>
</ul>
</li>
</ul>
</div>
<div class="main">
<div id="h1-1">
<h1>main header 1-1</h1>
<p>para 1</p>
<p>para 2</p>
</div>
<div id="h1-2">
<h1>main header 1-2</h1>
<p>para 3</p>
<p>para 4</p>
<div id="h2-1">
<h2>sub header 2-1</h2>
<p>para 5</p>
<p>para 6</p>
<p>para 7</p>
</div>
<div id="h2-2">
<h2>sub header 2-3</h2>
<p>para 8</p>
<p>para 9</p>
</div>
</div>
<div id="h1-3">
<h1>main header 1-3</h1>
<p>para 10</p>
<div id="h2-3">
<h2>sub header 2-3</h2>
<p>para 11</p>
<p>para 12</p>
</div>
</div>
</div>
</doc>
我写的xsl是为了得到这个输出,
<xsl:template match="doc">
<doc>
<div name="list">
<ul>
<xsl:for-each-group select="*" group-starting-with="h1">
<li><a href="h1-{count(preceding::h1)+1}"><xsl:apply-templates/></a>
<xsl:variable name="h2" select="current-group()[self::h2]"/>
<xsl:if test="$h2">
<ul>
<xsl:apply-templates select="$h2" mode="san"/>
</ul>
</xsl:if>
</li>
</xsl:for-each-group>
</ul>
</div>
<div class="main">
<xsl:for-each-group select="*" group-starting-with="h2">
<div id="h2-{count(preceding::h2)+1}">
<xsl:apply-templates select="current-group()[self::*]"/>
</div>
</xsl:for-each-group>
<xsl:for-each-group select="*" group-starting-with="h1">
<div id="h1-{count(preceding::h1)+1}">
<xsl:apply-templates select="current-group()[self::*]"/>
</div>
</xsl:for-each-group>
</div>
</doc>
</xsl:template>
<xsl:template match="h2" mode="san">
<li><a href="h2-{count(preceding::h2)+1}"><xsl:apply-templates/></a></li>
</xsl:template>
第一部分工作正常,但我遇到的问题是结果xml我加倍了内容,<div>
s内的id显示错误。
我得到了结果,
<doc>
<div name="list">
<ul>
<li><a href="h1-1">main header 1-1</a></li>
<li><a href="h1-2">main header 1-2</a>
<ul>
<li><a href="h2-1">sub header 2-1</a>
</li>
<li><a href="h2-2">sub header 2-3</a></li>
</ul>
</li>
<li>
<a href="h1-3">main header 1-3</a>
<ul>
<li><a href="h2-3">sub header 2-3</a></li>
</ul>
</li>
</ul>
</div>
<div class="main">
<div id="h2-1">
<h1>main header 1-1</h1>
<p>para 1</p>
<p>para 2</p>
<h1>main header 1-2</h1>
<p>para 3</p>
<p>para 4</p>
</div>
<div id="h2-1">
<h2>sub header 2-1</h2>
<p>para 5</p>
<p>para 6</p>
<p>para 7</p>
</div>
<div id="h2-2">
<h2>sub header 2-3</h2>
<p>para 8</p>
<p>para 9</p>
<h1>main header 1-3</h1>
<p>para 10</p>
</div>
<div id="h2-3">
<h2>sub header 2-3</h2>
<p>para 11</p>
<p>para 12</p>
</div>
<div id="h1-1">
<h1>main header 1-1</h1>
<p>para 1</p>
<p>para 2</p>
</div>
<div id="h1-2">
<h1>main header 1-2</h1>
<p>para 3</p>
<p>para 4</p>
<h2>sub header 2-1</h2>
<p>para 5</p>
<p>para 6</p>
<p>para 7</p>
<h2>sub header 2-3</h2>
<p>para 8</p>
<p>para 9</p>
</div>
<div id="h1-3">
<h1>main header 1-3</h1>
<p>para 10</p>
<h2>sub header 2-3</h2>
<p>para 11</p>
<p>para 12</p>
</div>
</div>
</doc>
任何人都可以建议我如何安排我的代码以获得预期的输出?
答案 0 :(得分:2)
I would use two functions to handle the two different grouping requirements:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.org/mf"
exclude-result-prefixes="xs mf"
version="2.0">
<xsl:output indent="yes"/>
<xsl:function name="mf:group-list" as="element()*">
<xsl:param name="elements" as="element()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:if test="$elements[self::*[local-name() eq concat('h', $level)]]">
<ul>
<xsl:for-each-group select="$elements" group-starting-with="*[local-name() eq concat('h', $level)]">
<li>
<a href="#{local-name()}-{count(preceding-sibling::*[local-name() eq local-name(current())]) + 1}">
<xsl:value-of select="."/>
</a>
<xsl:sequence select="mf:group-list(current-group() except ., $level + 1)"/>
</li>
</xsl:for-each-group>
</ul>
</xsl:if>
</xsl:function>
<xsl:function name="mf:group-div" as="element()*">
<xsl:param name="elements" as="element()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$elements" group-starting-with="*[local-name() eq concat('h', $level)]">
<xsl:choose>
<xsl:when test="self::*[local-name() eq concat('h', $level)]">
<div id="{local-name()}-{count(preceding-sibling::*[local-name() eq local-name(current())]) + 1}">
<xsl:copy-of select="."/>
<xsl:sequence select="mf:group-div(current-group() except ., $level + 1)"/>
</div>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="doc">
<xsl:copy>
<div name="list">
<xsl:sequence select="mf:group-list(h1 | h2 | h3 | h4 | h5 | h6, 1)"/>
</div>
<div class="main">
<xsl:sequence select="mf:group-div(*, 1)"/>
</div>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>