如何用XSLT 1.0统计XML中不同<tag>值的监狱数量?
使用XSLT 1.0(xmlstarlet)统计XML中不同值的监狱数量
数据结构
XML文件包含数千条监狱数据,结构示例如下:
<bases xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <marker> <name>United States Penitentiary, Canaan</name> <adr>Canaan</adr> <state>Pennsylvania</state> <geo>41.562778, -75.421389</geo> <tag>Federal</tag> <wiki>United_States_Penitentiary,_Canaan</wiki> </marker> <marker> <name>Mohawk Correctional Facility</name> <adr>Rome</adr> <state>New York</state> <geo>43.184511, -75.483992</geo> <tag>State</tag> <wiki>Mohawk_Correctional_Facility</wiki> </marker> ... </bases>
需求
需要统计<tag>标签下不同值(共8种,如Federal、State)对应的监狱数量,使用XSLT 1.0处理器(xmlstarlet)。
尝试过的代码及问题
- 最初尝试的代码无法得到正确结果:
<xsl:template match="/bases/marker[tag='Federal']"> TOTAL = <xsl:value-of select="count(.)"/> </xsl:template>
问题:该模板会匹配每个符合条件的<marker>节点,每次输出的count(.)都是1,最终会输出多个1而非总数。
- 单个值统计的代码可行:
<xsl:template match="/"> TOTAL = <xsl:value-of select="count(//bases/marker[tag='Federal']) "/> </xsl:template>
但扩展到多值统计时出现错误,比如统计State时结果为0(实际有数百条数据):
<xsl:template match="/"> Federal = <xsl:value-of select="count(//bases/marker[tag='Federal']) "/> State = <xsl:value-of select="count(//bases/marker[tag='Statel']) "/> </xsl:template>
问题:这里存在笔误,把State写成了Statel;同时手动逐个枚举8种tag值不仅繁琐,后续tag值变化时还需修改代码。
解决方案
方案1:修正笔误,手动统计所有tag值
若坚持手动统计,先修正拼写错误,确保每个tag值匹配正确:
<xsl:template match="/"> Federal = <xsl:value-of select="count(//bases/marker[tag='Federal']) "/> State = <xsl:value-of select="count(//bases/marker[tag='State']) "/> <!-- 继续添加其他6种tag值的统计行 --> </xsl:template>
方案2:使用Muenchian分组自动统计所有不同tag值(更高效)
XSLT 1.0中可通过Muenchian分组方法,自动识别所有不同的<tag>值并统计数量,无需手动枚举:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义分组键:基于tag的文本值 --> <xsl:key name="tag-group" match="marker" use="tag"/> <xsl:template match="/"> <xsl:for-each select="//bases/marker[generate-id() = generate-id(key('tag-group', tag)[1])]"> <!-- 输出tag值和对应的数量 --> <xsl:value-of select="tag"/> = <xsl:value-of select="count(key('tag-group', tag))"/> <xsl:text> </xsl:text> <!-- 添加换行,优化输出格式 --> </xsl:for-each> </xsl:template> </xsl:stylesheet>
使用xmlstarlet执行的命令
将上述XSLT保存为count-tags.xsl,执行以下命令即可得到统计结果:
xmlstarlet tr count-tags.xsl your-prison-data.xml
内容的提问来源于stack exchange,提问作者Ed S.
相关产品推荐
相关产品推荐

