2

我的 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>to <pub>( person/pubIdreferences 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>
    

第二个选项似乎更简洁和正确,但我无法让它工作。

有任何想法吗?

4

3 回答 3

1

使用这个 XPath 1.0 one-liner

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

person这将返回此文档中至少有一个子元素的元素的计数,pubId这样有一个pub元素的id属性字符串值等于该元素,pubId并且其open子元素的字符串值为 string "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
于 2012-08-31T12:33:56.203 回答
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 中,变量是不可变的,一旦设置就不能更改。因此,您尝试设置变量和增量的第一种方法是无效的。

于 2012-08-31T08:33:57.357 回答
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 ()))

但使用键更简单、更快捷。

于 2012-08-31T12:17:33.983 回答