我会选择管道设计。在第一阶段,对于给定的文档,收集所有@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-output 变量,您将求和,而不是计数。要访问 $phase-1-output 中的 lb-groups,您需要使用 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 属性对 testResults 的子元素进行计数
所需输出
因此,所需的输出将如下所示。我发明了非信息结构,因为 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 处理器。