我想使用xslt 将xhtml转换为dokuwiki语法。
现在,我无法解决的一件事就是如何处理嵌套列表。 dokuwiki语法对列表项使用星号(*),每个嵌套级别(c.f。wiki syntax)前面有两个空格。
我的问题:在以下示例中,< xsl:template mach =“li”> 如何与列表项目2.1匹配。 1 要注意它的嵌套级别,以便在前面添加适量的空格?
* list item 1
* list item 2
* list item 2.1
* list item 2.1.1
* list item 2.2
* list item 2.3
* list item 3
对应
以下html的显示方式如下:
<ul>
<li>
list item 1
</li>
<li>
list item 2
<ul>
<li>
list item 2.1
<ul>
<li>list item 2.1.1</li>
</ul>
</li>
<li>list item 2.2</li>
<li>list item 2.3</li>
</ul>
</li>
<li>
list item 3
</li>
</ul>
答案 0 :(得分:5)
以下转型:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vBlanks"
select="' '"/>
<xsl:variable name="vnNestSpaces" select="2"/>
<xsl:template match="li">
<xsl:variable name="vNestLevel"
select="count(ancestor::li)"/>
<xsl:value-of select=
"concat('
',
substring($vBlanks,1,$vnNestSpaces*$vNestLevel),
'* ', normalize-space(text()[1])
)"/>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
应用于原始XML文档:
<ul>
<li> list item 1
</li>
<li> list item 2
<ul>
<li> list item 2.1
<ul>
<li>list item 2.1.1</li>
</ul>
</li>
<li>list item 2.2</li>
<li>list item 2.3</li>
</ul>
</li>
<li> list item 3 </li>
</ul>
产生所需的结果:
* list item 1
* list item 2
* list item 2.1
* list item 2.1.1
* list item 2.2
* list item 2.3
* list item 3
请注意以下:
所需的缩进由count(ancesstor::li)
的值决定。
缩进的空间直接来自足够大的空白行(包含20个嵌套级别的空白)。 无需逐个递归地输出空格。
转换效率更高,原因是上述2.
请注意使用XPath substring()
函数。
答案 1 :(得分:2)
以下是我如何使用它:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="//li">
<xsl:call-template name="loop">
<xsl:with-param name="maxcount" select="count(ancestor::li)"/>
<xsl:with-param name="initial-value" select="0"/>
</xsl:call-template>
<xsl:text>* </xsl:text>
<xsl:value-of select="normalize-space(text())"/>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="ul/li" />
</xsl:template>
<xsl:template name="loop">
<xsl:param name="maxcount"/>
<xsl:param name="initial-value"/>
<xsl:if test="$initial-value < $maxcount">
<xsl:text>	</xsl:text>
<xsl:call-template name="loop">
<xsl:with-param name="maxcount" select="$maxcount"/>
<xsl:with-param name="initial-value" select="$initial-value+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
以下是它如何分解:
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
您需要确保XSLT的输出是文本,并且您还要删除任何现有的空格。
<xsl:template match="//li">
...
</xsl:template>
这是您的主要模板,会匹配文档中的每个<li>
。此模板的第一步是输出适当数量的制表符(可随意将其调整为空格或任何您需要的)。这样做的方法是调用自定义loop
模板,该模板将递归调用自身,从initial-value
循环到maxcount
,在每次迭代时输出制表符(	
)
<xsl:text>* </xsl:text>
<xsl:value-of select="normalize-space(text())"/>
<xsl:text>
</xsl:text>
此块只输出前面有*
和后面有换行符(
)的文本。请注意,我使用text()
函数而不是.
来检索节点的值。如果不这样做,父节点的输出将(根据W3C推荐)将所有子文本节点与父节点连接起来。
<xsl:apply-templates select="ul/li" />
最后,我们以递归方式调用当前模板,但明确引用下一个<li>
<ul>
的{{1}} - 这使我们不会在同一父元素上意外调用模板两次。