我是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>
我对所有已解析的文档都有相同的结构。
最后一个问题...... count函数正确返回一个文档的计数。但接下来的计数结果将与前一个结果相同。我的目标是对每次迭代的结果求和。
因此,如果我第一次迭代有15个匹配,第二次迭代有4个匹配,则计数变量将设置为154.
你能帮忙解决这个问题吗?
P.S。我正在计算 testResults 的子元素 lb 属性
P.p.s xsl 版本 1.0
谢谢, 瓦列
答案 0 :(得分:1)
我会选择管道设计。在第一阶段,对于给定的文档,收集所有的@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),它包含一个包含count和key的元素列表(lb-group)。在第一个模板中放置select表达式,你需要的是你需要的问题空间。
您可能拥有跨文档共享的@lb值,我认为您希望将这些值组合在一起并求和。因此,在阶段2中,您应用与阶段1中相同的分组和计数技术,除了输入来自$ phase-1-output变量,您将进行求和,而不是计数。要访问$ phase-1-output中的lb-groups,您需要使用node-set()函数。
如果这足够,请告诉我,或者您想要一个完整的样式表。
OP已经要求提供完整的样式表,所以就在这里。由于缺乏适当的样本数据,我制作了几个样本输入文档,其具有与OP提供的相同的显着特征,但是减少并简化为适合Q&amp;一个网站。
假设我们有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处理器。