【问题标题】:count how many tags follow a parent tag in xslt计算xslt中父标签后面有多少标签
【发布时间】:2012-11-18 00:55:30
【问题描述】:

我必须编写一个可与​​任何 XML 文档一起使用的 XSLT 文档,并将结果显示在 HTML 表中。表格的列都取决于 XML 文档中有多少标签。我正在尝试使用

<xsl:value-of select="count(/*/*/)"/> 

统计标签的数量。

但如果我有:

  <film>
      <title></title>
      <year></year>
      <actor></actor>
  </film>
  <film>
      <title></title>
      <year></year>
      <actor></actor>
  </film>

结果将是 3 而不是当前显示的 6。请问这个问题有什么解决办法吗?

【问题讨论】:

  • 使用following:: 轴怎么样?虽然我不太明白你在这里想要什么,所以我可能完全错了。

标签: xml xslt


【解决方案1】:

我。假设:

  1. 您有一个格式良好的 XML 文档,例如:

。 . . .

<films>
  <film>
    <title/>
    <year/>
    <actor/>
  </film>
  <film>
    <title/>
    <year/>
    <actor/>
  </film>
</films>

和:

.2。 film 元素都有相同数量的同名列,那么您只需要:

 count(/*/*[1]/*)

这会产生 XML 文档顶部元素的第一个子元素的子元素数量:

3

二。另一种可能性:不同的film 元素有不同数量的子元素,其中一个元素的所有子元素决定了表格的总列数。

<films>
  <film>
    <title/>
    <year/>
    <actor/>
  </film>
  <film>
    <title/>
    <year/>
    <actor/>
    <rating/>
    <director/>
  </film>
  <film>
    <title/>
    <year/>
    <actor/>
    <rating/>
  </film>
</films>

然后,使用 XPath 2.0,使用:

max(/*/*/count(*))

这会产生 XML 文档顶部元素的子元素拥有的最大子元素数:

5

三。最后,如果film 元素中没有一个可能包含列的所有元素,则使用(ABach 已经提出):

count(distinct-values(/*/*/*/name()))

【讨论】:

    【解决方案2】:

    我。 XSLT 1.0/XPath 1.0

    我不相信有办法使用纯 XPath 1.0 来做到这一点(因为您正在寻找不同的元素名称,我认为这些名称没有任何特定的顺序 [无论如何,我不喜欢依赖于某种顺序])。

    也就是说,您可以使用基于密钥的 XSLT 1.0 解决方案来解决问题。

    当这个 XSLT 1.0 文档:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output omit-xml-declaration="no" indent="yes" method="text"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:key name="kFilmChildren" match="film/*" use="name()"/>
    
      <xsl:template match="/">
        <xsl:value-of
          select="count(//film/*[
                    generate-id() = 
                    generate-id(key('kFilmChildren', name())[1])
          ])"/>
      </xsl:template>
    </xsl:stylesheet>
    

    ...应用于您的示例 XML(包装在根元素中):

    <films>
      <film>
        <title/>
        <year/>
        <actor/>
      </film>
      <film>
        <title/>
        <year/>
        <actor/>
      </film>
    </films>
    

    ...产生想要的结果:

    3
    

    如果我们对稍作修改的 XML 应用相同的样式表:

    <films>
      <film>
        <title/>
        <year/>
        <actor/>
        <test/>
      </film>
      <film>
        <title/>
        <year/>
        <actor/>
        <test/>
        <test2/>
      </film>
    </films>
    

    ...再次生成正确答案:

    5
    

    注意:鉴于您没有展示完整的文档,我通过使用 // 表达式来弥补知识的不足。然而,在非常大的树根附近,这可能是一项昂贵的操作。你最好让你的更具体。


    二。 XSLT 2.0/XPath 2.0

    Pure XPath 2.0 可以通过使用distinct-values 表达式来获得正确答案:

    count(distinct-values(//film/*/name()))
    

    XSLT 验证:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:output omit-xml-declaration="no" indent="yes" method="text" />
      <xsl:strip-space elements="*" />
    
      <xsl:template match="/">
         <xsl:value-of select="count(distinct-values(//film/*/name()))" />
      </xsl:template>
    
    </xsl:stylesheet>
    

    结果:

    3
    

    【讨论】:

      【解决方案3】:

      您的文档实际上包含 16 个标签:8 个开始标签和 8 个结束标签。所以我怀疑“计算标签”不是你真正的要求。由于您的术语不正确,我们只能猜测您的真实需求。我怀疑它可能是制作一个表格,每个不同的元素名称都有一行,其中包含具有该名称的元素数量的计数。这将是:

      <table>
        <xsl:for-each-group select="//*" group-by="name()">
          <tr>
            <td><xsl:value-of select="current-grouping-key()"/></td>
            <td><xsl:value-of select="count(current-group()"/></td>
          </tr>
        </xsl:for-each-group>
      </table>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多