XSL用于展平嵌套列表

时间:2011-03-02 21:09:07

标签: xml xslt xpath

这与我几个月前提出的问题相反。我有一个嵌套的结构,我需要展平。例如,输入可能是这样的:

<root>
  <h1>text</h1>
    <ol>
        <li>num1</li>
        <li>num2 
              <ol>
            <li>sub-num1</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>

输出应该按如下方式展平:

<root>
   <h1>text</h1>
   <list level="1">num1</list>
   <list level="1">num2</list>
   <list level="2">sub-num1</list>
   <list level="2">sub-num2</list>
   <list level="3">sub-sub-num1</list>
   <list level="1">num3</list>
   <p>text</p>
   <list level="1">num1</list>
   <list level="1">num2</list>
   <h2>text</h2>
</root>

我想我可以用一种不优雅的方式做到这一点,但我希望有人可能有更好的方法来分享。这需要使用XSLT 1.0

完成

4 个答案:

答案 0 :(得分:4)

此样式表:

<xsl:stylesheet version="1.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="ol">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="li">
        <list level="{count(ancestor::ol)}">
            <xsl:apply-templates select="node()[not(self::ol)]"/>
        </list>
        <xsl:apply-templates select="ol"/>
    </xsl:template>
</xsl:stylesheet>

输出:

<root>
    <h1>text</h1>
    <list level="1">num1</list>
    <list level="1">num2                
    </list>
    <list level="2">sub-num1</list>
    <list level="2">sub-num2                                            
    </list>
    <list level="3">sub-sub-num1</list>
    <list level="1">num3</list>
    <p>text</p>
    <list level="1">num1</list>
    <list level="1">num2</list>
    <h2>text</h2>
</root>

答案 1 :(得分:2)

使用Oxygen / XML和您的输入进行测试。如果嵌套的OL在之前和之后都有文本,则没有指定您想要发生的内容;在这种情况下,所有文本都将在嵌套项之前输出。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
  exclude-result-prefixes="xs xd"
  version="2.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ol">
    <xsl:param name="level" as="xs:integer" select="0"/>
    <xsl:apply-templates select="li">
      <xsl:with-param name="level" select="$level+1"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="li">
    <xsl:param name="level" as="xs:integer"/>
    <list level="{$level}"><xsl:value-of select="normalize-space(string-join(text(),' '))"/></list>
    <xsl:apply-templates select="ol">
      <xsl:with-param name="level" select="$level"/>
    </xsl:apply-templates>
  </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:1)

您要求的

XSLT 1.0 解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ol">
        <xsl:apply-templates select="@* | node()"/>
    </xsl:template>

    <xsl:template match="li">
        <list level="{count(ancestor::li) + 1}">
            <xsl:value-of select="text()"/>
        </list>
        <xsl:apply-templates select="*"/>
    </xsl:template>
</xsl:stylesheet>

针对您的样本的正确结果是:

<root>
    <h1>text</h1>
    <list level="1">num1</list>
    <list level="1">num2</list>
    <list level="2">sub-num1</list>
    <list level="2">sub-num2</list>
    <list level="3">sub-sub-num1</list>
    <list level="1">num3</list>
    <p>text</p>
    <list level="1">num1</list>
    <list level="1">num2</list>
    <h2>text</h2>
</root>

答案 3 :(得分:0)

谢谢Jim,你让我走上正轨。我稍微修改了样式表,因为我需要在<li>元素中应用模板。我还删除了level参数,因为这个值可以通过计算祖先来获得。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="xs xd" version="2.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ol">
        <xsl:if test="not(ancestor::ol)">
            <xsl:apply-templates/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="li">
        <list level="{count(ancestor::ol)}">
            <xsl:apply-templates/>
        </list>
        <xsl:apply-templates select="ol" mode="passThrough"/>
    </xsl:template>

    <xsl:template match="ol" mode="passThrough">
        <xsl:apply-templates/>
    </xsl:template>

</xsl:stylesheet>