2013-05-20 62 views
-1

我需要一個腳本來遞歸地瀏覽一個目錄,並按照最頻繁到最不頻繁的順序解析每個.xml文件和列表標籤,並告訴每個標籤出現的次數爲了統計哪些是最常用的。解析.xml文件和列表標籤的腳本[求助]

我在想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; 

但我有定義$桶變量麻煩文檔中的單詞一個Perl腳本,該腳本intendend定義像

$bucket = "monkey | tree | banana" 

,輸出會像

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

在我來說,我不得不使用通配符所以它會分析在<之間>一切都像

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

但是這會創建一個包含所有的XML代碼和計數每一個「<」和「>」添加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; 

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 

謝謝大家的幫助,這是非常有益的,一到cfrenz因爲他把他的博客至極的代碼我editted

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

+0

我d爲此使用Perl,但這主要是個人偏好,我不會爲您編寫整個程序。 CPAN上不缺少XML庫。你有什麼嘗試?你遇到了什麼問題? – Quentin

+0

我實際上是perl的新手,我有點迷路。我仍然試圖找出這樣做的邏輯,只有這樣我才能夠在代碼中進行轉換。我已經做了一個按文件名列出並計數重複但我分配了什麼名字太尋找。在這裏我不知道有多少個不同的標籤我會找到,所以我需要找到一種方法來打印遇到的每個標籤,說'<' and a '/>'之間的所有內容,並打印它與該標籤 –

+0

的發行版我正在考慮使用glob函數。你怎麼看? –

回答

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或只是調用每個文件的腳本使用查找或其他。


要執行你需要的XQuery處理器,在這個例子中,我將提出開源軟件BaseX;你也可以使用所有其他的XQuery引擎。確保安裝它,以便您擁有命令行包裝器;通過下載和安裝或使用Debian和Ubuntu中的「basex」軟件包。

商店上面的文件,這裏test.xq,並呼籲使用find腳本調用它在當前文件夾中的每個XML文件:

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

這將打印統計每個文件。

+0

謝謝Jens Erat,但我該如何運行該腳本? –

+0

用一個小例子擴展我的答案。我敢打賭,在正確解析XML時,Perl在6個合理的分割代碼行中將無法做到這一點。 –

+0

我應該替換test.xq腳本中的任何東西嗎? –

2

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 

輸出示例:

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 
... 

更新:

變體 「<和>之間提取一切」,但仍使用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/> 

是不是像你想要的東西?

+0

我該如何運行?對不起,但我是一個linux和編程的新手 –

+0

複製並粘貼所有四行到命令行,就像你用我的一樣。 –

+0

感謝它的工作,但無論如何要列出< and />之間的整條線? –

0

爲您提供

<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工具的工作輸入(這是沒有有效的XML):

$ sort <input.txt |uniq -c 

這將返回:

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

非常感謝Jens Erat,但我知道了 –

+0

任何有關如何使其遞歸的建議?我有一個包含多個子目錄的目錄,其中包含一個[Content_Type] .xml文件。我希望腳本解析這些文件中的每一個。 –

+0

開始_learning_關於您正在使用的工具。你需要用'find'完成同樣的事情我現在提出了其中兩個答案,閱讀'man find'如何使用它,如果你自己表現出努力並且不成功,隨時可以提出一個新問題,在[su]這部分更適合的地方可能會更好(這不是關於編程,而是關於使用程序)。 –