使用XSLT将XHTML转换为维基语法

3
我想使用XSLT将XHTML转换为DokuWiki语法。现在,我无法处理的一个问题是如何处理嵌套列表。DokuWiki语法使用星号(*)表示列表项,每个嵌套级别前面有两个空格(参见wiki语法)。我的问题是:在下面的示例中,如何使匹配列表项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

对应于

  • 列表项1
  • 列表项2
    • 列表项2.1
      • 列表项2.1.1
    • 列表项2.2
    • 列表项2.3
  • 列表项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>
2个回答

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('&#xA;',
               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

请注意以下内容:
1. 所需缩进由 count(ancesstor::li) 的值决定。
2. 缩进空间直接从足够大的空白行中获取(包含足够多的空格以便嵌套20层)。无需逐个递归输出空格。
3. 由于第2点,转换更加高效。
4. 注意使用XPath substring() 函数。

非常好!!我喜欢空行的想法 - 我知道一定有更好的方法来获得缩进。 - Andrew Hare

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>&#xd;</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 &lt; $maxcount">
            <xsl:text>&#x9;</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-valuemaxcount循环,每次迭代输出一个制表符(&#x9;)来完成的。
<xsl:text>* </xsl:text>
<xsl:value-of select="normalize-space(text())"/>
<xsl:text>&#xd;</xsl:text>

这段代码简单地输出带有星号*的文本,并在之后添加一个换行符(&#xd;)。请注意,我使用了text()函数而不是.来获取节点的值。如果你不这样做,父节点的输出将会(根据W3C建议)将所有子文本节点与父节点连接起来。

<xsl:apply-templates select="ul/li" />

最后,我们递归调用当前模板,但明确引用下一个是 <ul> 的直接子级的 <li> - 这可以防止我们意外地在同一父元素上两次调用模板。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接