对不起,我是xml处理的新手……我有以下内容:
<divisions>
<division>
<divisionName>D1</divisionName>
<subdivisions>
<subdivision>
<subdivisionName>SD1</subdivisionName>
<values>
<value>1</value>
</values>
</subdivision>
<subdivision>
<subdivisionName>SD2</subdivisionName>
<values>
<value>1</value>
<value>2</value>
</values>
</subdivision>
</subdivisions>
</division>
<division>
<divisionName>D2</divisionName>
<subdivisions>
<subdivision>
<subdivisionName>SD3</subdivisionName>
<values>
<value>2</value>
<value>2</value>
</values>
</subdivision>
</subdivisions>
</division>
</divisions>
我想使用XPath或XQuery转换为一个平面文件,其中按分区和细分求和。因此对于上面的结果将是:
D1 SD1 1
D1 SD2 3
D2 SD3 4
我的实际文件大约有700万行,所以我对是否有必要使用某种流形式的解析以及XPath或XQuery的性能最佳感兴趣。
我尝试了许多XQuery,但发现很难按高阶循环进行分组:
for all divisions
for all subdivisions
print divisionName, subdivisionName, sum(values)
任何见解表示赞赏!
答案 0 :(得分:1)
您可以使用此简单的XQuery。 declare
语句仅用于设置正确的输出模式。
xquery version "1.0";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "text";
let $db := doc("test.xml")/divisions
for $x in $db/division, $y in $x//subdivision
return concat(distinct-values($x/divisionName), ' ', distinct-values($y/subdivisionName), ' ', sum($y/values/value),'
')
其输出(经过Saxon-9测试)
D1 SD1 1
D1 SD2 3
D2 SD3 4
我没有将它与XSLT实现进行比较,但是此查询相对简单,因此我猜它很快。
答案 1 :(得分:1)
认为我知道了这一点(也删除了空格):
for $divisionName in distinct-values(//divisionName)
for $subdivisionName in distinct-values(//subdivisionName)
return concat($divisionName,$subdivisionName,sum(//division[divisionName = $divisionName]//subdivision[subdivisionName = $subdivisionName]//value),'
')
答案 2 :(得分:0)
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="divisions">
<xsl:for-each select="division">
<xsl:for-each select="subdivisions/subdivision">
<xsl:value-of select="ancestor::subdivisions/preceding-sibling::divisionName"/><xsl:text> </xsl:text>
<xsl:value-of select="subdivisionName"/><xsl:text> </xsl:text>
<xsl:value-of select="sum(values/value)"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
You may try in xslt
答案 3 :(得分:0)
尚不清楚是否需要分组(因为division
中有重复的subdivision
元素和/或重复的division
元素),如果您没有重复项,可以使用(XQuery 3.1)
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method 'text';
declare option output:item-separator ' ';
for $d in divisions/division,
$sd in $d/subdivisions/subdivision
return $d/divisionName/data() || ' ' || $sd/subdivisionName/data() || ' ' || sum($sd/values/value)
https://xqueryfiddle.liberty-development.net/bFukv8j
如果您需要分组,则将XQuery用作group-by
子句,例如
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method 'text';
declare option output:item-separator ' ';
for $d in divisions/division
group by $dn := $d/divisionName
for $sd in $d/subdivisions/subdivision
group by $dn, $sdn := $sd/subdivisionName
return $dn || ' ' || $sdn || ' ' || sum($sd/values/value)
https://xqueryfiddle.liberty-development.net/bFukv8j/2
关于性能,您可能需要检查所选的XQuery处理器,在XQuery数据库中,它始终取决于我认为的数据库组织和索引。
XSLT 3已进行流处理,但是由于您的元素在子元素中具有分组键,因此您需要复制项目:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode streamable="yes"/>
<xsl:output method="text" />
<xsl:template match="divisions">
<xsl:for-each-group select="division!copy-of()!subdivisions/subdivision" composite="yes" group-by="ancestor::division/divisionName, subdivisionName">
<xsl:value-of select="current-grouping-key(), sum(current-group()/values/value)" separator=" "/>
<xsl:text> </xsl:text>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>