用于解析.xml文件和列表标记的脚本

时间:2013-05-20 08:33:35

标签: xml list parsing

我需要一个脚本来递归遍历目录,并按照最频繁到最不频繁的顺序解析每个.xml文件和列表标记,并告诉每个标记出现多少次以便对其进行统计最常用的。

我在想Perl,但如果你认为有更好的方法请告诉我。

我能够找到一个用于计算文档中单词的perl脚本

sub by_count {
   $count{$b} <=> $count{$a};
}

open(INPUT, "<[Content_Types].xml");
open(OUTPUT, ">output");
$bucket = "";

while(<INPUT>){
   @words = split(/\s+/);
   foreach $word (@words){
            if($word=~/($bucket)/io){

      print OUTPUT "$word\n";
      $count{$1}++;}

   }
}
foreach $word (sort by_count keys %count) {

   print OUTPUT "$word occurs $count{$word} times\n";

}

close INPUT;
close OUTPUT;

但是我在定义$ bucket变量时遇到了问题,这个脚本是用来定义桶的

$bucket = "monkey | tree | banana"

,输出就像

word monkey occurs 4 times
word monkey occurs 3 times
word monkey occurs 1 times

在我的情况下,我必须使用通配符,因此它会解析介于两者之间的所有内容&lt;&gt;像

$bucket = <"<*"."*>">; 

但这会创建一个包含所有xml代码的输出文件,并计算每个&#34;&lt;&#34;和&#34;&gt;&#34;添加了toguether和输出

occurs 50 times

我需要做以下事情:

示例.xml文档:

<tag1 This is tag1 />
<tag1 This is tag1 />
<tag2 This is tag2 />
<tag2 This is tag2 />
<tag1 This is tag1 />
<tag2 This is tag2 />
<tag3 This is tag3 />

输出:

<tag1 This is tag1 /> appears 2 times 
<tag2 This is tag2 /> appears 3 times 
<tag3 This is tag3 /> appears 1 time

解决:

#usr/bin/perl

sub by_count {
   $count{$b} <=> $count{$a}; 
}

open(INPUT, "</file.xml"); #xml file
open(OUTPUT, ">outputfile"); #Create an output file
$bucket = qw/./;


while(<INPUT>){
   @words = split(/\</); #Whenever reaches a '<' breaks the string

   foreach $word (@words){
            if($word=~/($bucket*>)/io){

      #print OUTPUT "$word";
      #print OUTPUT "\n\n";
      $count{$1}++;}

   }
}
foreach $word (sort by_count keys %count) {

   print OUTPUT "<$word occurs $count{$word} times\n\n";

}

close INPUT;
close OUTPUT;

输出

<Default Extension="xlsx" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"/> occurs 1 times

<Default Extension="png" ContentType="image/png"/> occurs 1 times

<Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/> occurs 1 times

谢谢大家的帮助,这真的很有帮助,对于他在我编辑的博客上的代码来说,这是一个非常有用的

http://perlgems.blogspot.pt/2012/05/normal-0-false-false-false-en-us-x-none_2673.html

3 个答案:

答案 0 :(得分:3)

只是用一种用于查询XML文件的语言示例,XQuery:

for $element in //*
let $name := $element/local-name()
group by $name
order by count($element) descending
return concat($name, ": ", count($element))

如何将其应用于多个XML文档取决于您正在使用的查询处理器,具体取决于您的需求,您可以在XQuery中执行此操作,或者只使用find或其他任何内容为每个文件调用脚本。


要执行,您需要一个XQuery处理器,对于此示例,我将提出开源软件BaseX;你也可以使用所有其他XQuery引擎。确保安装它,以便您也拥有命令行包装器;通过下载和安装或使用Debian和Ubuntu中的“basex”软件包。

将上面的脚本存储在一个文件中,此处为test.xq,并调用use find为当前文件夹中的每个XML文件调用它:

find . -name "*.xml" -exec basex -i {} test.xq \;

它将打印每个文件的统计信息。

答案 1 :(得分:2)

使用xml2的Oneliner:

find . -type f -name '*.xml' -print0 | \
    xargs -0 -n 1 sh -c 'xml2 < "$0"' | \
    grep -v '/@' | cut -d=  -f 1 | uniq | grep -o '[^/]\+$' | \
    sort | uniq -c | sort -rn

示例输出:

  48376 id
  16125 username
  16125 title
  16125 timestamp
  16125 sha1
  16125 ns
  16106 text
  14711 page
  10436 comment
   8032 minor
   4978 data
   4977 track
   4977 timecode
   4455 BlockGroup
   2262 ReferenceBlock
   1414 sitename
   1414 namespace
   1414 generator
   1414 case
   1414 base
    385 SimpleBlock
    142 discardable
    137 Timecode
    130 Cluster
    126 keyframe
     40 !
     38 name
     28 TrackType
...

更新:

Variant“提取&lt;和&gt;之间的所有内容”,但仍使用xml2正确处理XML:

find . -type f -name '*.xml' -print0 | xargs -0 -n 1 sh -c 'xml2 < "$0"' | sed 's!^\([^@=]*\)=.*!\1=!'  | 2xml | sed 's!>!>\n!g' | grep -v '^</' | sed 's!^<!!; s!/\?>!!;' | sort | uniq -c | sort -rn

示例输出:

   4986 id
   1662 username
   1662 title
   1662 timestamp
   1662 sha1
   1662 revision
   1662 page
   1662 ns
   1662 contributor
   1303 comment
    631 minor
    170 text xml:space="preserve" bytes="72"
     84 sitename
     84 siteinfo
     84 namespaces
     84 namespace key="9" case="first-letter"
     84 namespace key="8" case="first-letter"
     84 namespace key="7" case="first-letter"
     84 namespace key="6" case="first-letter"
     84 namespace key="5" case="first-letter"
...

更新2 了解您想要的其他尝试:

我的输入样本:

<q>
    <w tag="11"/>
    <w tag="22"/>
    <r/>
    <r/>
    <w tag="22"/>
    <w/>
    <w/>
    <w>ignore me
    </w>
    <r   />
    <ololo>
        <r />
        <!--
        <w tag="33"/>
        -->
    </ololo>
</q>

脚本:

cat q.xml | xml2  | sed 's!^\([^@=]*\)=.*!\1=!' | grep -v '/!=' | 2xml | xmllint -format - | sed 's/^\s*//g' | grep -v '^</\|^$' | sed 's!/\?>$!/>!' | sort | uniq -c | sort -rn

输出:

  4 <r/>
  3 <w/>
  2 <w tag="22"/>
  1 <?xml version="1.0"?/>
  1 <w tag="11"/>
  1 <q/>
  1 <ololo/>

这是你想要的吗?

答案 2 :(得分:0)

对于您提供的输入(没有有效的XML)

<tag1 This is tag1 />
<tag1 This is tag1 />
<tag2 This is tag2 />
<tag2 This is tag2 />
<tag1 This is tag1 />
<tag2 This is tag2 />
<tag3 This is tag3 />

您可以使用基本的unix工具:

$ sort <input.txt |uniq -c

这将返回:

3 <tag1 This is tag1 />
3 <tag2 This is tag2 />
1 <tag3 This is tag3 />