XSLT count()包括引用节点比较

时间:2012-08-31 08:25:01

标签: xml xslt xpath

我的XML代码(包含酒吧和人):

<document>
    <pubs>
        <pub id="pub1">
            <open>true</open>
        </pub>
        <pub id="pub2">
            <open>false</open>
        </pub>
    </pubs>
    <people>
        <person>
            <name>John</name>
            <pubId>pub1</pubId>
        </person>
        <person>
            <name>Paul</name>
            <pubId>pub2</pubId>
        </person>
    </people>
</document>

使用<person><pub>person/pubId引用pub[@id])的引用。酒吧本身有一个布尔<open>(说明酒吧是打开还是关闭)。

使用XSLT,我希望能够count()可以去酒吧的人数。要前往酒吧,酒吧的<open>值必须为true

我无法编写的两种可能的解决方案:

  1. 通过人员进行迭代并跟踪数字:

    <xsl:for-each select="person">
        <xsl:variable name="pId" select="pubId" />
    
        <xsl:if test="root()/document/pubs/pub[@pubId=$pId]/open = 'true'" >
            <!-- any way to keep track of this number? -->
        </xsl:if>
    </xsl:for-each>
    
  2. 直接使用count()函数:

    <count>
        <xsl:value-of select="count(//person[root()/document/pubs/pub[@id = pubId]/open = 'true'])" />
    </count>
    
  3. 第二个选项似乎更简洁和正确,但我无法让它工作。

    有什么想法吗?

3 个答案:

答案 0 :(得分:1)

使用此XPath 1.0一行

count(/*/people/person[pubId = /*/pubs/pub[open = 'true']/@id])

这将返回此文档中至少有一个person子元素的pubId元素的数量,以便有一个pub元素,其id属性的字符串值等于pubId及其open子项的字符串值为字符串"true"

以下是基于XSLT的验证

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
  <xsl:copy-of select=
      "count(/*/people/person[pubId = /*/pubs/pub[open = 'true']/@id])"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<document>
    <pubs>
        <pub id="pub1">
            <open>true</open>
        </pub>
        <pub id="pub2">
            <open>false</open>
        </pub>
    </pubs>
    <people>
        <person>
            <name>John</name>
            <pubId>pub1</pubId>
        </person>
        <person>
            <name>Paul</name>
            <pubId>pub2</pubId>
        </person>
    </people>
</document>

评估Xpath表达式并将此评估结果复制到输出中:

1

答案 1 :(得分:0)

您可以尝试使用密钥查找酒吧

<xsl:key name="pubs" match="pub" use="@id" />

这样您就可以将计数简化为以下

<xsl:value-of select="count(//person[key('pubs', pubId)[open='true']])"/>

因此,对于以下XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="pubs" match="pub" use="@id" />
   <xsl:template match="/">
      <count>
         <xsl:value-of select="count(//person[key('pubs', pubId)[open='true']])"/>
      </count>
   </xsl:template>
</xsl:stylesheet>

以下是输出

<count>1</count>

请注意,在XSLT中,变量是不可变的,一旦设置就无法更改。因此,您尝试设置变量和增量的第一种方法无效。

答案 2 :(得分:0)

是的,第二种方法是正确的:它基本上是在进行连接。正如Tim C指出的那样,密钥通常对在XSLT中进行连接很有用。

您尝试的原因

count(//person[root()/document/pubs/pub[@id = pubId]/open = 'true'])

不起作用是'pubId'的上下文是错误的。您可以使用范围变量在XPath 2.0中解决此问题:

count(for $p in //person return (if (/document/pubs/pub[@id = $p/pubId]/open = 'true') then $p else ()))

但使用键更简单,更快。