2014-01-30 231 views
1

我在TREC format中有7GB XML文檔。該文件有標籤DOC,其中有DOCNOTEXT根據ID列表篩選XML文檔

<FILE> 
<DOC> 
<DOCNO>abc</DOCNO> 
<TEXT>content 
of first 
doc</TEXT> 
</DOC> 
<DOC> 
<DOCNO>def</DOCNO> 
<TEXT>content 
of second 
doc</TEXT> 
</DOC> 
<DOC> 
<DOCNO>ghi</DOCNO> 
<TEXT>content 
of third 
doc</TEXT> 
</DOC> 
</FILE> 

我想這個文件過濾和保持DOC有S IN一個文件一個DOCNO包含ID列表:

abc 
ghi 

所以輸出變成

<FILE> 
<DOC> 
<DOCNO>abc</DOCNO> 
<TEXT>content 
of first 
doc</TEXT> 
</DOC> 
<DOC> 
<DOCNO>ghi</DOCNO> 
<TEXT>content of 
third 
doc</TEXT> 
</DOC> 
</FILE> 

我的猜測是xml_grep應該是有用的,但我做不到。

+0

你可以嘗試使用'XMLStarlet'來獲取'DOC'元素,'awk'來檢查和pri nt只有'DOCNO'等於'abc,ghi'的元素。你有沒有嘗試過,或者你需要它在bash? – tftd

+0

謝謝@ tftd。我只想強調,ID列表在一個文件中。有400萬人。 – mossaab

+0

我不確定我是否遵循,你想獲得'DOCNO'內容並將它存儲到一個文件中,或者你想獲得所有'DOC'元素,其中'DOCNO'包含某個字符串?關於你的文件的長度 - 這是很多數據。根據系統的不同,解析和存儲所有內容可能需要一段時間。 – tftd

回答

3

如果您有xml_grep我假設也安裝了模塊XML::Twig。我不知道該怎麼xml_grep的作品,但你可以實現相同的結果有一個完整的腳本,如:

#!/usr/bin/env perl 

use warnings; 
use strict; 
use XML::Twig; 

XML::Twig->new(
    twig_print_outside_roots => 1, 
    twig_roots => { 
     'DOC' => sub { 
      my $docno = $_->next_elt('DOCNO') || next; 
      if ($docno->text_only =~ m/\A(?:abc|ghi)\Z/) { 
       $_->print; 
      } 
     }, 
    }, 
    pretty_print => 'indented', 
)->parsefile(shift); 

它搜索每<DOC>元素,讀取下一個並提取其文本,即相比於abcghi使用正則表達式,並且只在匹配的情況下打印該部分樹。

運行它想:

perl script.pl xmlfile 

國債收益率(注意空格,因爲他們的任何元素是沒有意義的):

<FILE> 

    <DOC> 
    <DOCNO>abc</DOCNO> 
    <TEXT>content 
of first 
doc</TEXT> 
    </DOC> 


    <DOC> 
    <DOCNO>ghi</DOCNO> 
    <TEXT>content 
of third 
doc</TEXT> 
    </DOC> 
</FILE> 
+0

謝謝比雷。我確實有XML :: Twig,但我想強調一下,id列表位於文件中。有400萬人。 – mossaab

+2

@mossaab:改變這個問題是微不足道的。打開文件,逐行閱讀並保存每個單詞作爲散列的關鍵字。然後用一個散列檢查來更改正則表達式比較,如:if(exists $ word {$ docno-> text_only}){...}' – Birei

2

使用awk來創建XPath和xmlstarlet過濾該文件:

$ xpath=$(awk ' 
      BEGIN {printf "//DOC[not("} 
      {printf "%sDOCNO=\"%s\"", sep, $0; sep=" or "} 
      END {print ")]"} 
     ' ids.txt) 

$ echo "$xpath" 
//DOC[not(DOCNO="abc" or DOCNO="ghi")] 

$ xmlstarlet ed -O -d "$xpath" file.xml 
<FILE> 
    <DOC> 
    <DOCNO>abc</DOCNO> 
    <TEXT>content 
of first 
doc</TEXT> 
    </DOC> 
    <DOC> 
    <DOCNO>ghi</DOCNO> 
    <TEXT>content 
of third 
doc</TEXT> 
    </DOC> 
</FILE> 
+0

這看起來像一個工作解決方案。但'xmlstarlet'會消耗所有可用的12G內存,然後掛起。我想它在處理之前必須讀取整個7G文件。 – mossaab

+1

xpath表達式也會非常怪異。最好和Birei一起回答。 –