首页 > 解决方案 > XSLT 转换 xml 带有子列表的列表项

问题描述

将感谢您的帮助。我有如下的xml:

 <ul>
    <li>list item 1 </li>
    <li>List Item 2 
         <ul>
            <li>List item 2.1</li>
            <li>List Item 2.2</li>
        </ul>
    </li>
    <li>List Item 3 </li>
</ul>

输出应如下所示:

<list>
        <item>
            <paragraph>list item 1 </paragraph>
        </item>
        <item>
            <paragraph>List Item 2 </paragraph>
            <list>
                <item>
                    <paragraph>List<emphasis> item</emphasis> 2.1 </paragraph>
                </item>
                <item>
                    <paragraph>List Item 2.2 </paragraph>
                </item>
            </list>
        </item>
        <item>
            <paragraph>List Item 3 </paragraph>
        </item>
    </list>

我正在使用 xlst 3.0 版,如下所示:

<xsl:template match="ul">
    <xsl:choose>
        <xsl:when test="name(..)='li'">
            <xsl:text disable-output-escaping="yes">&lt;/paragraph&gt;</xsl:text>
            <list>
                <xsl:apply-templates/>
            </list>
        </xsl:when>
        <xsl:otherwise>
            <list>
            <xsl:apply-templates/>
        </list></xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="li">
    <item>
        <xsl:text disable-output-escaping="yes">&lt;paragraph&gt;</xsl:text>
        <xsl:apply-templates/>
        <xsl:text disable-output-escaping="yes">&lt;/paragraph&gt;</xsl:text>
    </item>
</xsl:template>

我几乎得到了我想要的输出,但有额外的结束段落元素(</paragraph>)如下:

<list>
              <item><paragraph>list item 1 </paragraph></item>
              <item><paragraph>List Item 2 </paragraph><list>
                          <item><paragraph>List item 2.1 </paragraph></item>
                          <item><paragraph>List Item 2.2 </paragraph></item>
                    </list>
        </paragraph></item>
              <item><paragraph>List Item 3 </paragraph></item>
        </list>

标签: xslt

解决方案


您应该避免disable-output-escaping以这种方式使用。正如您所见,这确实不是一个好习惯。

对于给定的 XML,您可以做的是使用匹配的模板,text()然后将其包装paragraph起来:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:output method="xml" indent="yes""/>

  <xsl:strip-space elements="*" />

  <xsl:template match="ul">
    <list>
      <xsl:apply-templates/>
    </list>
  </xsl:template>

  <xsl:template match="li">
    <item>
        <xsl:apply-templates/>
    </item>
  </xsl:template>

  <xsl:template match="text()">
    <paragraph>
        <xsl:value-of select="normalize-space()" />
    </paragraph>
  </xsl:template>
</xsl:stylesheet>

或者,如果您可以在文本中添加标记,例如<li>list <b>item 1</b> </li>,并且您想要输出类似<paragraph>list<b>item 1</b></paragraph>,那么您可以使用xsl:for-each-group.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:output method="xml" indent="yes" />

  <xsl:strip-space elements="*" />

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="ul">
    <list>
      <xsl:apply-templates/>
    </list>
  </xsl:template>

  <xsl:template match="li">
    <item>
      <xsl:for-each-group select="node()" group-ending-with="ul">
        <paragraph>
          <xsl:apply-templates select="current-group()[not(self::ul)]" />
        </paragraph>
        <xsl:apply-templates select="current-group()[self::ul]" />
      </xsl:for-each-group>
    </item>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="normalize-space()" />
  </xsl:template>
</xsl:stylesheet>

推荐阅读