XSLT - 计算每个 xml 文档的节点数



我是xsl的新手,在多个xml文档中计算节点时遇到了问题。这是我的 XSLT 片段:

<xsl:variable name="count">
    <xsl:for-each select="document(./log/@file)/testResults/*[not(@lb = preceding::*/@lb)]">
            <xsl:value-of select="count(../*[@lb = current()/@lb])"/>
    </xsl:for-each>
</xsl:variable>

其中 ./log/@file 处理很少的 XML 文档。一个 xml 文档示例:

<testResults version="1.2">
        <sample t="63" lt="0" ts="1343919489839" s="true" lb="jp@gc - Dummy Sampler" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="114"/>
        <sample t="62" lt="0" ts="1343919489903" s="true" lb="jp@gc - Dummy Sampler" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="114"/>
        <sample t="58" lt="0" ts="1343919490063" s="true" lb="jp@gc - Dummy Sampler" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="114"/>
        <sample t="13" lt="0" ts="1343919490210" s="true" lb="jp@gc - Dummy Sampler" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="114"/>
        <sample t="37" lt="0" ts="1343919490223" s="true" lb="jp@gc - Dummy Sampler" rc="200" rm="OK" tn="Thread Group 1-1" dt="text" by="114"/>
</testResults>

我对所有解析的文档都有相同的结构。

最后还有一个问题...计数函数正确返回一个文档的计数。但是下一个计数结果将与前一个计数结果连接。我的目标是对每次迭代的结果求和。

因此,如果我第一次迭代有 15 个马切,第二次迭代有 4 个匹配项,则计数变量将设置为 154。

你能帮忙吗?

附言我正在按 lb 属性分组计算测试结果子元素

P.p.s xsl 版本是 1.0

谢谢瓦列里

我会选择管道设计。在第一阶段,对于给定的文档,收集所有@lb计数,如下所示......

<xsl:variable name="phase-1-output">
  <xsl:apply-templates select="..some-expression.../@file" mode="phase-1">
</xsl:variable>
<template match="@file" mode="phase-1">
 <xsl:apply-templates select="document(.)/testResults/sample" mode="phase-1" />
</template>
<xsl:template match="*" mode="phase-1" />
<xsl:template match="testResults/*[not(@lb = preceding::*/@lb)]" mode="phase-1" >
 <lb-group key="{@lb}">
  <xsl:number count="../*[@lb = current()/@lb]" />
 <lb-group>
</xsl:variable>

这给了我们一个变量($phase-1-output),其中包含一个包含计数和键的元素列表(lb-group)。将第一个模板中的选择表达式替换为问题空间所需的表达式。

您可能有跨文档共享的@lb值,我认为您希望将它们组合在一起并相加。因此,在阶段 2 中,您将应用与阶段 1 中相同的分组和计数技术,只是输入来自 $phase-1 输出变量,您将求和,而不是计数。要访问 $phase-1 输出中的 lb 组,您需要使用 node-set() 函数。

让我知道这是否足够,或者你想要一个完整的样式表。


更新

OP 要求提供完整的样式表,所以就在这里。由于缺乏提供的适当示例数据,我制作了几个示例输入文档,这些文档具有与OP提供的相同功能,但根据问答网站进行了削减和简化。

输入

假设我们有 2 个输入文件。第一个带有 URL in1.xml的文件包含以下内容:

<testResults category="citrus">
 <sample lb="lemon" />
 <sample lb="lemon" />
 <sample lb="green apple" />
 <sample lb="green apple" />
 <sample lb="green apple" />
</testResults>

另一个带有 URL in2.xml的文件包含以下内容:

<testResults category="green food">
 <sample lb="green apple" />
 <sample lb="celery soup" />
 <sample lb="peas" />
 <sample lb="peas" />
</testResults>

OP的既定要求是...

按 lb 属性分组计算测试结果的子元素

所需输出

因此,所需的输出将如下所示。我发明了非信息结构,因为 OP 忘记提供它。

<root>
   <lb-group lb-key="lemon">2</lb-group>
   <lb-group lb-key="green apple">4</lb-group>
   <lb-group lb-key="celery soup">1</lb-group>
   <lb-group lb-key="peas">2</lb-group>
</root>

读者会注意到有 4 个青苹果。 3 个来自第一个输入文档,1 个来自第二个输入文档。我假设 OP 想要跨文件边界计数。如果需要分离,也就是说,严格按文件计算,请告诉我。

解决方案

在 Saxon XSLT 处理器上,在向后兼容模式下,此结果可以通过以下 XSLT 1.0 样式表实现,该样式表实现了上述管道线设计。

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:so="http://stackoverflow.com/questions/11847434"
  xmlns:exslt="http://exslt.org/common"
  exclude-result-prefixes="xsl so exslt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="test-result-files">
 <so:file file="in1.xml" />
 <so:file file="in2.xml" />
</xsl:variable>
<xsl:template match="/" >
 <root>
  <xsl:variable name="phase-1-output" >
    <xsl:apply-templates select="document('')/*/xsl:variable
      [@name='test-result-files']/so:file/@file" mode="phase-1" />
  </xsl:variable>
  <xsl:apply-templates select="$phase-1-output/lb-group" mode="phase-2" />
 </root>
</xsl:template>
<xsl:template match="@file" mode="phase-1">
 <xsl:apply-templates select="document(.)/testResults/sample" mode="phase-1" />
</xsl:template>
<xsl:template match="*" mode="phase-1" />
<xsl:template match="testResults/*[not(@lb = following::*/@lb)]" mode="phase-1" >
 <xsl:variable name="lb-key" select="@lb" />
 <lb-group lb-key="{$lb-key}">
  <xsl:number count="*[@lb = $lb-key]" />
 </lb-group>
</xsl:template>    
<xsl:template match="*" mode="phase-2" />
<xsl:template match="lb-group[not(@lb-key = following::*/@lb-key)]" mode="phase-2">
 <xsl:copy>
  <xsl:copy-of select="@*" />
  <xsl:value-of select="sum(../*[@lb-key=current()/@lb-key])" />
 </xsl:copy>
</xsl:template>
</xsl:stylesheet> 

警告

根据您的 XSLT 引擎是什么,您可能需要更换该行...

  <xsl:apply-templates select="$phase-1-output/lb-group" mode="phase-2" />

。跟。。。

  <xsl:apply-templates select="xslt:node-set($phase-1-output)/lb-group" mode="phase-2" />

。或Microsoft等效值(如果使用 MS 处理器)。

相关内容

  • 没有找到相关文章