XSLT - 选择相同元素的块

时间:2016-05-31 13:17:44

标签: xml xslt

我试图改变这种XML:

<!--- potential other elements before-->
<li>bla</li>
<li>bli</li>
<li>blo</li>
<anytag/>
<li>pla</li>
<li>pli</li>
<li>plo</li>

成:

<!--- potential other elements before-->
<ul>
 <li>bla</li>
 <li>bli</li>
 <li>blo</li>
</ul>
<anytag/>
<ul>
 <li>pla</li>
 <li>pli</li>
 <li>plo</li>
</ul>

所以基本上,选择所有兄弟姐妹<li>,其中没有任何其他元素。

我正在使用XSLT 2.0。

所以我想做的事情如下:

<xsl:template match="li[1]">
    <ul>
      <li>
        <xsl:value-of select="." />
      </li>
      <xsl:apply-templates select="following-sibling::li[preceding-sibling::node()][1]" mode="add-to-ul"/>
    </ul>
  </xsl:template>

<xsl:template match="li"  mode="add-to-ul">
    <li>
      <xsl:value-of select="." />
    </li>
  </xsl:template>

  <xsl:template match="li">
  </xsl:template>

首先,这看起来并不太优雅,但是由于li [1]如果我有几个列表,它就会失败,显然是不行的。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

在XSLT 2.0中,您可以使用xsl:for-each-group指令轻松分组。

例如:

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

<xsl:template match="root">
    <root>
        <xsl:for-each-group select="*" group-adjacent="boolean(self::li)">  
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <ul>
                        <xsl:copy-of select="current-group()"/> 
                    </ul>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="current-group()"/> 
                </xsl:otherwise>  
            </xsl:choose>
        </xsl:for-each-group>
    </root>
</xsl:template>

</xsl:stylesheet>

请注意,这需要从父节点的上下文中调用(在您的示例中未显示)。

答案 1 :(得分:3)

以下是纯XSLT 1.0解决方案(更短更简单)可以在任何浏览器中执行

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kGroup" match="li" 
          use="generate-id(preceding-sibling::*[not(self::li)][1])"/>

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

  <xsl:template match="li[not(preceding-sibling::*[1][self::li])]">
    <ul>
      <xsl:copy-of select="key('kGroup', generate-id(preceding-sibling::*[1]))"/>
    </ul>
  </xsl:template>
  <xsl:template match="li"/>
</xsl:stylesheet>

将此转换应用于以下XML文档

<t>
    <a/>
    <b/>
    <li>bla</li>
    <li>bli</li>
    <li>blo</li>
    <anytag/>
    <li>pla</li>
    <li>pli</li>
    <li>plo</li>
    <c/>
</t>

产生了想要的正确结果

<t>
   <a/>
   <b/>
   <ul>
      <li>bla</li>
      <li>bli</li>
      <li>blo</li>
   </ul>
   <anytag/>
   <ul>
      <li>pla</li>
      <li>pli</li>
      <li>plo</li>
   </ul>
   <c/>
</t>

第二部分。处理多级嵌套列表

对转型进行一点调整:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kGroup" match="li" 
      use="concat(generate-id(..), generate-id(preceding-sibling::*[not(self::li)][1]))"/>

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

  <xsl:template match="li[not(preceding-sibling::*[1][self::li])]">
    <ul>
      <xsl:apply-templates  mode="li" select=
      ". | key('kGroup', concat(generate-id(..), 
                            generate-id(preceding-sibling::*[not(self::li)][1]))
          )
           [position() >1]"/>
    </ul>
  </xsl:template>
  <xsl:template match="*" mode="li">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="li"/>
</xsl:stylesheet>

允许我们正确处理多个深度的嵌套列表,例如

<t>
    <a/>
    <b/>
    <li>bla</li>
    <li>bli
      <a>
            <li>gla</li>
            <li>gli</li>
            <d>
              <li>glo</li>
            </d>
      </a>
    </li>
    <li>blo</li>
    <anytag/>
    <li>pla</li>
    <li>pli</li>
    <li>plo</li>
    <c/>
</t>

并生成想要的正确结果

<t>
   <a/>
   <b/>
   <ul>
      <li>bla</li>
      <li>bli
      <a>
            <ul>
               <li>gla</li>
               <li>gli</li>
            </ul>
            <d>
               <ul>
                  <li>glo</li>
               </ul>
            </d>
         </a>
      </li>
      <li>blo</li>
   </ul>
   <anytag/>
   <ul>
      <li>pla</li>
      <li>pli</li>
      <li>plo</li>
   </ul>
   <c/>
</t>