嘿,我有一个简单的xml文件:
<?xml version="1.0"?>
<accidents>
<accident>
<org>1</org>
<com>194</com>
<dep>010</dep>
<grav>0.64</grav>
</accident>
<accident>
<org>1</org>
<com>194</com>
<dep>420</dep>
<grav>0.54</grav>
</accident>
<accident>
<org>1</org>
<com>44</com>
<dep>010</dep>
<grav>0.4</grav>
</accident>
</accidents>
我想应用xslt 1.0来计算dep的事故数量:输出应该是这样的:
dep 010:2起事故;dep 420:1起事故
谢谢,注意我使用php,所以saxon不能使用
此转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kAccByDept" match="accident" use="dep"/>
<xsl:template match=
"accident
[generate-id()
=
generate-id(key('kAccByDept', dep)[1])
]">
<xsl:if test="position() > 1"> ; </xsl:if>
<xsl:value-of select=
"concat('dep ', dep, ' : ',
count(key('kAccByDept', dep)), ' accidents')
"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
应用于所提供的XML文档时:
<accidents>
<accident>
<org>1</org>
<com>194</com>
<dep>010</dep>
<grav>0.64</grav>
</accident>
<accident>
<org>1</org>
<com>194</com>
<dep>420</dep>
<grav>0.54</grav>
</accident>
<accident>
<org>1</org>
<com>44</com>
<dep>010</dep>
<grav>0.4</grav>
</accident>
</accidents>
生成所需的正确结果:
dep 010 : 2 accidents ; dep 420 : 1 accidents
解释:
分组的Muenchian方法。
推送样式的XSLT处理。
更新:OP没有真正的XSLT处理器——他的工具没有实现xsl:key
在这种情况下,以下解决方案(注意,这比Muenchian分组效率低得多)仍然解决了问题,产生了确切的所需输出:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match=
"accident
[not(dep
=
preceding-sibling::*/dep
)
]
">
<xsl:value-of select=
"concat('dep ', dep, ' : ',
count(following-sibling::*[dep = current()/dep]) +1,
' accidents')
"/>
<xsl:if test=
"following-sibling::*/dep
[not(. = current()/dep)
and
not(.
=
../preceding-sibling::*/dep)
]"> ; </xsl:if>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
当应用于相同的XML文档(如上)时,会产生相同的正确结果:
dep 010 : 2 accidents ; dep 420 : 1 accidents
不确定为什么要使用XSLT,但如果必须这样做,您可以更容易地从PHP值创建dom元素:
$dom = new DOMDocument;
$dom->loadXML(file_get_contents('accidents.xml'));
$xpath = new DOMXPath($dom);
$deps = array();
foreach ($xpath->query('/accidents/accident/dep') as $node) {
$n = $node->nodeValue;
if (!isset($deps[$n])) {
$deps[$n] = 0;
}
$deps[$n]++;
}
这给出了一个以"dep"为键、以事故编号为值的数组。
使用:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="k" match="accident" use="dep"/>
<xsl:template match="/accidents">
<xsl:apply-templates select="accident[generate-id() = generate-id(key('k', dep))]"/>
</xsl:template>
<xsl:template match="accident">
<xsl:value-of select="concat('dep ', dep, ' : ', count(key('k', dep)), ' accidents; ')"/>
</xsl:template>
</xsl:stylesheet>
无Muenchian方法的解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/accidents">
<xsl:apply-templates select="accident[not(preceding-sibling::accident/dep = dep)]"/>
</xsl:template>
<xsl:template match="accident">
<xsl:value-of select="concat('dep ', dep, ' : ', count(../accident[dep = current()/dep]), ' accidents; ')"/>
</xsl:template>
</xsl:stylesheet>
输出:
dep 010 : 2 accidents; dep 420 : 1 accidents;
我不得不承认,我不确定为什么使用密钥的解决方案不适合你,但这里有一个不适合,它可能是一个变通方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="list">
<xsl:apply-templates />
</xsl:variable>
<xsl:value-of select="substring($list,1,string-length($list)-2)" />
</xsl:template>
<xsl:template match="accident">
<xsl:if test="not(preceding-sibling::accident[dep = current()/dep])">
<xsl:value-of select="concat('dep ',dep,' : ',count(. | following-sibling::accident[dep = current()/dep]),' accidents ;')" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
它只在accident
元素之前没有具有相同dep
的同级元素的情况下输出,对其自身和具有相同dep
的所有后续accident
元素进行计数。它将结果分配给一个变量,然后使用子字符串截断尾部的;
。如果这实际上不是一个问题,那么可以很容易地完全忽略match="/"
模板。