程序来分析很多XML

pup*_*eno 3 xml

我有很多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>&#xA;</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>&#xA;</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使用名为的模板启动进程,maindir参数设置为file:///path/to/your/directory?select=*.xml并将输出发送到report.txt.