XSLT统计具有特定值的元素数量

24
我需要计算XML文件中具有特定值的元素数量(以验证唯一性)。 XML文件如下所示:

编辑:我已更新原始“简化”的XML,使用了实际混乱的设计。不幸的是,这将使所有以前的答案变得混乱和错误,除非进行编辑。

<root>
  <ac>
   <Properties>
     <Property Name="Alive">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>11007</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
     <Property Name="Dead">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>11008</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
     ...
     <Property Name="MostlyDeadAllDay">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>99001</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
   </Properties>
  </ac>
</root>

我试图定义一个变量,以查看在模板参数中定义的长值(ID)有多少个处于生/死级别的属性。以下是类似的代码(尽管我怀疑这是错误的)...

<xsl:param name="parPropId"/>
<xsl:variable name="countProperties">
   <xsl:value-of select="count(/root/ac/
      Properties/Property/
      Properties/Property[@Name = 'ID']/
      Properites/Property[@Name = 'Value']/long = $parPropId)"/>
</xsl:variable>

在“ID”级别下可以定义多个属性元素。但我相当确定,在“ID”下只能有一个属性元素(“Value”),在“Value”下只能有一个“long”元素。

[免责声明]设计整个XML文件的人真的不知道如何构建XML结构(例如,反向使用属性与元素)。恐怕我的XSLT思维因此暂时被扭曲了:)


为什么你展示的XPath表达式是“错误”的?我没有看出任何问题。 - Cerebrus
不确定。我简化了上面的XML。实际的xpath是这样的:“///Properties/Property/Properties/Property[@Name = 'ID']/Properties/Property[@Name = 'Value']/long”。如果你是正确的,我可以用“/long”替换“[long = $parPropId]”。这似乎是错误的,因为这将把两个“[]”操作放在一起。 - e-holder
我验证了vartec的text()函数可以正确获取文本(即"///Properties/Property/Properties/Property[@Name = 'ID']/Properties/Property[@Name = 'Value']/long/text()"可以获取我的ID),但是使用他的方法计算数量仍然失败。 - e-holder
我也尝试过“count(...Property[(@Name = 'Value') and (long/text() = $parPropId)])”,但这总是返回0。我认为这里充分体现了埃德定律,“行为越古怪,错误越愚蠢”。 - e-holder
似乎我们缺少的是您实际XML的横截面。如果我们看到我们需要查询的内容,答案可能会更准确。我建议编辑您的答案并替换“简化”的XML片段。 - Cerebrus
3个回答

43

这个 XPath:

count(//Property[long = '11007'])

返回与以下相同的值:

count(//Property/long[text() = '11007'])

除了第一个计算符合条件的Property节点之外,第二个计算符合条件的long子节点。

根据您的评论和多次阅读您的问题,我认为您想要基于多个条件找到唯一性。因此,实际上,我认为您实际上正在检查多个条件。以下方法也可以:

count(//Property[@Name = 'Alive'][long = '11007'])

因为它的意思与以下内容相同:

count(//Property[@Name = 'Alive' and long = '11007'])

当然,您需要在模板中替换参数的值。上面的代码只是为了说明这一点。 编辑(问题编辑后)
你对 XML 非常正确,它实际上是一个彻头彻尾的 编程恐惧症 候选者!我不得不一直重新计数来跟踪当前的“Property”节点。我感同身受!
count(/root/ac/Properties/Property[Properties/Property/Properties/Property/long = $parPropId])

请注意,我已删除所有其他检查(ID和Value)。由于您能够使用XML中的层次结构到达相关节点,因此似乎不需要这些检查。此外,您已经提到唯一性检查仅基于long元素的内容。

感谢您教我这个XPath等价性!你们说的一切都很有道理(基于我的适度XSL / XPath经验)。实际上,我没有多个标准,ID是我关心的全部。只是无法让计数给出非零值[arrrgghh]。 - e-holder
令人惊讶的是,这些小丑有时会使用“string”和“int”而不是只用“long”来表示这些ID。你已经激励我去提交给CodingHorror了!我最终删除了你解决方案中的“/long”部分(现在可以工作了)。我将此标记为答案,并非常感谢你一路以来的耐心帮助。 - e-holder

2

您的xpath有点偏差:

count(//Property/long[text()=$parPropId])

编辑:Cerebrus非常正确地指出,你在OP中使用节点的隐含值的代码对于你的目的来说是绝对没问题的。实际上,由于你很可能想要使用“Property”节点而不是“long”节点,所以向请求//Property[long=$parPropId]比text() xpath更好,尽管从可读性的角度来看,你可以为后者提出论据。

我能说什么呢,我今天有点累了 :)


1
猜猜看!你现在有了666个答案!非常显著! - Cerebrus
不巧的是,Annakata再次删除了任何解释他/她答案真正错误的评论。 - Dimitre Novatchev
是的,我确实遇到了一个问题,就是不提供200行响应来覆盖那些0.01%的边缘情况,以防问问题的人无法进行智能分析。你是个英雄Dimitree。 - annakata
有时候,你的答案失败得比不覆盖0.01%的边缘情况还要糟糕。你最大的失败在于不接受批评并且不利用它来改进。如果任何答案存在问题,我都会立即做出反应。回答问题不是为了迅速积累声望。删除这个棘手的评论? :) - Dimitre Novatchev
你在指责我刷声望?你?你的个人资料显示你25%的投票是反对的,其中很多都是针对我,这些投票意在表明一个答案是完全错误或误导性的,而这显然不是。你公然使用反对票来推动你的回答上升... - annakata
显示剩余5条评论

-2
<xsl:variable name="count" select="count(/Property/long = $parPropId)"/>

未经测试,但我认为应该可以工作。我假设属性节点是根节点的直接子节点,因此为了提高性能,我去掉了您的后代选择器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接