前一段时间我问了一个非常相似的问题([1]:XSL to create nested list from flat tree problem“从扁平树问题创建嵌套列表”,但我的问题略有扩展。最初我没有考虑嵌套在列表中的段落。现在,输入:
<root>
<h1>text</h1>
<list level="1">num1</list>
<list level="1">num2</list>
<para type="indent">indented para1</para>
<list level="2">sub-num1</list>
<para type="indent">sub-indented para1</para>
<para type="indent">sub-indented para2</para>
<list level="2">sub-num2</list>
<list level="3">sub-sub-num1</list>
<list level="1">num3</list>
<p>text</p>
<list>num1</list>
<list>num2</list>
<h2>text</h2>
</root>
我需要这个输出:
<root>
<h1>text</h1>
<ol>
<li>num1</li>
<li>num2
<paragraph>indented para1</paragraph>
<ol>
<li>sub-num1
<paragraph>sub-indented para1</paragraph>
<paragraph>sub-indented para2</paragraph>
</li>
<li>sub-num2
<ol>
<li>sub-sub-num1</li>
</ol>
</li>
</ol>
</li>
<li>num3</li>
</ol>
<p>text</p>
<ol>
<li>num1</li>
<li>num2</li>
</ol>
<h2>text</h2>
</root>
也可能有缩进段落的实例不在列表中,但我想我可以在我把这只猴子背上后解决这个问题。 我需要使用XSLT 1.0,再次感谢任何帮助。
答案 0 :(得分:3)
对我的previus answer没有太多修改,这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kListByParent"
match="list"
use="concat(generate-id(
preceding-sibling::*[
not(self::list|self::para)
][1]
), '+',
generate-id(
preceding-sibling::list[
current()/@level > @level
][1]
)
)"/>
<xsl:key name="kParaByList" match="para"
use="generate-id(preceding-sibling::list[1])"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*" mode="copy">
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="list[preceding-sibling::*[1][
self::list|self::para
]
] |
para"/>
<xsl:template match="list">
<xsl:variable name="vListMark"
select="generate-id(preceding-sibling::*[1])"/>
<ol>
<xsl:apply-templates select="key('kListByParent',
concat($vListMark,'+'))"
mode="makeLi">
<xsl:with-param name="pListMark" select="$vListMark"/>
</xsl:apply-templates>
</ol>
</xsl:template>
<xsl:template match="list" mode="makeLi">
<xsl:param name="pListMark"/>
<xsl:variable name="vSubList"
select="key('kListByParent',
concat($pListMark,'+',generate-id()))"/>
<li>
<xsl:apply-templates
select="node()|key('kParaByList',generate-id())"
mode="copy"/>
<xsl:if test="$vSubList">
<ol>
<xsl:apply-templates select="$vSubList" mode="makeLi">
<xsl:with-param name="pListMark"
select="$pListMark"/>
</xsl:apply-templates>
</ol>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
输出:
<root>
<h1>text</h1>
<ol>
<li>num1</li>
<li>num2
<para type="indent">indented para1</para>
<ol>
<li>sub-num1
<para type="indent">sub-indented para1</para>
<para type="indent">sub-indented para2</para>
</li>
<li>sub-num2
<ol>
<li>sub-sub-num1</li>
</ol>
</li>
</ol>
</li>
<li>num3</li>
</ol>
<p>text</p>
<ol>
<li>num1</li>
<li>num2</li>
</ol>
<h2>text</h2>
</root>
注意:从概念上讲,此应该以list
开头递归分组,最小@level
。我将重构它以使其在语义上更准确。
编辑:在语义上更接近XSLT 2.0解决方案。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="node()"
group-adjacent="boolean(self::list|self::para)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:call-template name="makeList">
<xsl:with-param name="pList"
select="current-group()"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template name="makeList">
<xsl:param name="pList"/>
<xsl:variable name="vFirstList" select="($pList/self::list)[1]"/>
<xsl:apply-templates
select="$pList[not(. >> $vFirstList)] except $vFirstList"/>
<xsl:if test="$vFirstList">
<ol>
<xsl:for-each-group select="$pList[not($vFirstList >> .)]"
group-starting-with="list[not($vFirstList/@level ne @level)]">
<li>
<xsl:value-of select="current-group()[1]"/>
<xsl:if test="current-group()[2]">
<xsl:call-template name="makeList">
<xsl:with-param name="pList"
select="current-group()[position()!=1]"/>
</xsl:call-template>
</xsl:if>
</li>
</xsl:for-each-group>
</ol>
</xsl:if>
</xsl:template>
</xsl:stylesheet>