我有很多XML文件,我想从它们生成一个报告.报告应提供以下信息:
root 100%
a*1 90%
b*1 80%
c*5 40%
Run Code Online (Sandbox Code Playgroud)
这意味着所有的文件有一个根元素,90%具有一个一个在根元素,80%具有一个b在根元素,40%具有5组Ç中的元素b.
例如,如果某些文档有4个c元素,大约5个和6个,它应该说:
c*4.3 4 6 40%
Run Code Online (Sandbox Code Playgroud)
这意味着40%有4到6个c元素,平均值是4.3.
我正在寻找免费软件,如果它不存在我会写它.我即将这样做,但我考虑过检查它.我可能不是第一个必须分析并获得数千个XML文件的结构概述的人.
Jen*_*niT 11
这是一个XSLT 2.0方法.
假设$docs包含要扫描的文档节点序列,则需要为文档中显示的每个元素创建一行.你可以<xsl:for-each-group>这样做:
<xsl:for-each-group select="$docs//*" group-by="name()">
<xsl:sort select="current-group-key()" />
<xsl:variable name="name" as="xs:string" select="current-grouping-key()" />
<xsl:value-of select="$name" />
...
</xsl:for-each-group>
Run Code Online (Sandbox Code Playgroud)
然后你想在文件中找出该元素的统计数据.首先,找到文件中包含该名称的元素:
<xsl:variable name="docs-with" as="document-node()+"
select="$docs[//*[name() = $name]" />
Run Code Online (Sandbox Code Playgroud)
其次,您需要在每个文档中包含该名称的元素数量的序列:
<xsl:variable name="elem-counts" as="xs:integer+"
select="$docs-with/count(//*[name() = $name])" />
Run Code Online (Sandbox Code Playgroud)
现在你可以做计算了.平均的,最小和最大可与被计算avg(),min()和max()功能.百分比只是包含元素的文档数除以格式化的文档总数.
把它放在一起:
<xsl:for-each-group select="$docs//*" group-by="name()">
<xsl:sort select="current-group-key()" />
<xsl:variable name="name" as="xs:string" select="current-grouping-key()" />
<xsl:variable name="docs-with" as="document-node()+"
select="$docs[//*[name() = $name]" />
<xsl:variable name="elem-counts" as="xs:integer+"
select="$docs-with/count(//*[name() = $name])" />
<xsl:value-of select="$name" />
<xsl:text>* </xsl:text>
<xsl:value-of select="format-number(avg($elem-counts), '#,##0.0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number(min($elem-counts), '#,##0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number(max($elem-counts), '#,##0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number((count($docs-with) div count($docs)) * 100, '#0')" />
<xsl:text>%</xsl:text>
<xsl:text>
</xsl:text>
</xsl:for-each-group>
Run Code Online (Sandbox Code Playgroud)
我在这里没有做的是根据元素的深度缩进线条.我刚按字母顺序排列元素,为您提供统计数据.有两个原因:首先,在某种结构中显示元素统计数据反映出它们在文档中的显示方式(尤其是因为不同的文档可能具有不同的结构),因此显着更难(就像在这里写的那样).其次,在许多标记语言中,文档的精确结构是不可知的(因为,例如,部分可以在部分内嵌套到任何深度).
我希望它仍然有用.
更新:
需要XSLT包装器和一些运行XSLT的指令吗?好.首先,开始使用Saxon 9B.
您需要将要分析的所有文件放在目录中.Saxon允许您使用特殊URI语法使用集合访问该目录(或其子目录)中的所有文件.如果您想要递归搜索或过滤您通过文件名查看的文件,那么值得查看该语法.
现在完整的XSLT:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="dir" as="xs:string"
select="'file:///path/to/default/directory?select=*.xml'" />
<xsl:output method="text" />
<xsl:variable name="docs" as="document-node()*"
select="collection($dir)" />
<xsl:template name="main">
<xsl:for-each-group select="$docs//*" group-by="name()">
<xsl:sort select="current-group-key()" />
<xsl:variable name="name" as="xs:string" select="current-grouping-key()" />
<xsl:variable name="docs-with" as="document-node()+"
select="$docs[//*[name() = $name]" />
<xsl:variable name="elem-counts" as="xs:integer+"
select="$docs-with/count(//*[name() = $name])" />
<xsl:value-of select="$name" />
<xsl:text>* </xsl:text>
<xsl:value-of select="format-number(avg($elem-counts), '#,##0.0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number(min($elem-counts), '#,##0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number(max($elem-counts), '#,##0')" />
<xsl:text> </xsl:text>
<xsl:value-of select="format-number((count($docs-with) div count($docs)) * 100, '#0')" />
<xsl:text>%</xsl:text>
<xsl:text>
</xsl:text>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
运行它你会做类似的事情:
> java -jar path/to/saxon.jar -it:main -o:report.txt dir=file:///path/to/your/directory?select=*.xml
这告诉Saxon使用名为的模板启动进程,main将dir参数设置为file:///path/to/your/directory?select=*.xml并将输出发送到report.txt.