3

我想使用 xslt 将 xhtml 转换为 dokuwiki 语法

现在,我似乎无法解决的一件事是如何处理嵌套列表。dokuwiki 语法对列表项使用星号 (*),每个嵌套级别前面有两个空格(参见wiki 语法)。

我的问题:在以下示例中,与列表项 2.1.1匹配的<xsl:template mach="li">如何知道它的嵌套级别,以便预先添加适量的空格?

* 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>
4

2 回答 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. 注意 XPathsubstring()函数的使用。

于 2009-01-22T23:45:41.410 回答
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-valueto循环,在每次迭代maxcount时输出一个制表符 ( )。&#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" />

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

于 2009-01-22T17:45:02.930 回答