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

用于解析.xml文件和列表标记的脚本,xml,list,parsing,Xml,List,Parsing,我需要一个脚本递归地遍历一个目录,解析每个.xml文件,并按从最频繁到较不频繁的顺序列出标记,告诉每个标记出现多少次,以便统计哪些标记是最常用的 我在考虑Perl,但如果您认为有更好的方法,请告诉我 我能够找到一个perl脚本来计算文档中的单词 sub by_count { $count{$b} <=> $count{$a}; } open(INPUT, "<[Content_Types].xml"); open(OUTPUT, ">output"); $buck

我需要一个脚本递归地遍历一个目录,解析每个
.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;
结果是

word monkey occurs 4 times
word monkey occurs 3 times
word monkey occurs 1 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
出现2次
出现3次
出现1次

已解决:

#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;
#usr/bin/perl
按单位计数{
$count{$b}$count{$a};
}
打开(输入,“输出文件”)#创建一个输出文件
$bucket=qw/;
while(){
@words=split(/\)/io){
#打印输出“$word”;
#打印输出“\n\n”;
$count{$1}++;}
}
}
foreach$word(按\u计数键%count排序){

打印输出“仅举一个用于查询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处理器,在本例中,我将推荐开源软件;您也可以使用所有其他XQuery引擎。请确保安装它,这样您也可以使用命令行包装器;或者下载并安装,或者使用Debian和Ubuntu中的“basex”包

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

find . -name "*.xml" -exec basex -i {} test.xq \;
它将打印每个文件的统计信息。

Oneliner使用xml2:

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
更新:

“提取<和>”之间的所有内容,但仍使用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
更新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
cat q.xml | xml2 | sed's!^\([^@=]*\)=.!\1=!'| grep-v'/!='| 2xml | xmllint-format-| sed's/^\s*///g'| grep-v'^$!/>| 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/>
4
3.
2.
1.
1.
1.
1.

它是否与您想要的类似?

对于您提供的输入(它不是有效的XML)


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

$ sort <input.txt |uniq -c


$sort我会使用Perl,但这主要是我个人的偏好,我不会为您编写整个程序。CPAN上并不缺少XML库。您尝试了什么?遇到了什么问题?我实际上是Perl新手,有点不知所措。我仍在试图找出实现这一点的逻辑,只有到那时我才知道我将能够在代码中转换它。我已经做了一个按文件名列出并计算重复次数的操作,但我也指定了名称。在这里,我不知道我将找到多少不同的标记,因此我需要找到一种方法来打印遇到的每个标记,说出“”之间的所有内容,并打印出我正在考虑使用的标记的出现频率glob函数。你认为呢?XML不是一种常规语言,你不能使用正则表达式解析它——至少在没有关于文件结构限制的专门知识的情况下是这样。如果你想使用perl,可以使用一些XML SAX库,在开始标记上添加一个侦听器,并在每次该侦听器获得cal时在其名称上的哈希中增加一个计数器led。是的,但我认为我可以像解析普通文本一样解析它,过滤介于“”之间的所有内容。这不起作用吗?谢谢Jens Erat,但我该如何运行该脚本?用一个小示例扩展了我的答案。我敢打赌,在正确解析XML时,Perl将无法在6行合理的代码中完成这项工作。我应该替换test.xq脚本中的任何内容吗?我在ubuntu fork中使用sudo-apt-get-install-baseX安装了baseX,并且安装了它。但是当我运行find.-name“*.xml”-exec-baseX-I{}test.xq\;命令时,我得到了一个错误:[警告]/usr/bin/basex:无法在/usr/share/javas中找到/usr/share/java/tagsoup.jar。不知道为什么它想在未安装的情况下使用tagsoup。最简单的方法是安装推荐的包
libtagsoup java
。我应该如何运行它?抱歉,我是linux的新手,正在编程将所有四行复制并粘贴到命令line,就像你对我的一个所做的那样。谢谢它工作正常,但是是否仍然可以列出之间的整行?要查看属性,可以删除
grep-v'/@
chunk。属性howewer将不会与其元素相关联。更新了将元素绑定到属性的解决方案。虽然没有完全测试,但脚本可以修改我可以排除一些属性,或者只使用属性名(而不是值)。非常感谢Jens Erat,但我已经弄明白了关于如何使其递归的任何建议?我有一个包含多个子目录的目录,所有这些目录中都有一个[Content_Type].xml文件。我想让脚本解析这些文件中的每一个。开始学习您正在使用的工具。您需要使用
find
做完全相同的事情。我现在为其中两个答案提出了建议,请阅读
man find
了解如何使用它,如果您自己付出了努力但没有成功,请随时提出新问题,可能是这一部分在哪里更合适(不是关于编程,而是关于使用程序)。好的,我会接受你的建议,非常感谢。很抱歉,我是一个新手,但我刚刚开始实习,以前从未编程过。
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"
...
<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/>
<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 />
$ sort <input.txt |uniq -c
3 <tag1 This is tag1 />
3 <tag2 This is tag2 />
1 <tag3 This is tag3 />