2014-03-28 45 views
1

我有一個巨大的xml文件(幾GB),我可以用xml_split分割,或者我可以用xml_grep提取相關的子節點。如果我嘗試讀取整個XML,則會耗盡內存。分割或grep後保留XML名稱空間

但是,當我嘗試解析其中一個分割文件或grep:ed文件時,出現錯誤「名稱空間前綴xx on yy未定義」成千上萬次。

有沒有辦法將名稱空間定義從原始文件複製到splitted或grep:ed文件?或者我誤解了錯誤?

我對XML很陌生,我發現XML :: TWIG很有用。這裏是我使用的grep命令:

xml_grep --root 'SubInformation' --cond 'SubInformationName[string()="Blah"]' Infile.xml > Outfile.xml 

回答

1

您使用哪個工具來分析split(或grep)的結果? xmllint(來自libxml2)抱怨,但xmlwf(從expat)沒有。所以我認爲任何基於expat的工具都適用於XML,但不是基於libxml2的工具。

看起來像xml_splitxml_grep雖然可以聲明命名空間。至少它應該是一個選擇。我會看看它。

在此期間,這裏是進行後處理您xml_grep得到結果的quick'n骯髒的方式:

xml_grep --root 'SubInformation' --cond 'SubInformationName[string()="Blah"]' Infile.xml | perl -MXML::Twig -e'XML::Twig->new(start_tag_handlers => { xml_grep => sub { $_->set_att("xmlns:m" => "http://m.org") }, SubInformation => sub { $_->flush } })->parse(\*STDIN)' > Outfile.xml 

更換xmlns:m"http://m.org"用適當的值。

讓我想想一個以通用方式完成此操作的方法,其結果爲xml_split。我可以假定名稱空間聲明不是太棘手(即前綴(es)只聲明一次)?

編輯:這裏是添加命名空間聲明從xml_split產生的文件,把它作爲add_ns Infile您已經在Infile.xml運行xml_split後一種方式:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

my $root= shift @ARGV; 

my($base, @files)= sort glob("$root-*.xml"); 

my %ns= ns_for_file($base); 

foreach my $file (@files) 
    { add_ns($file, %ns); } 


sub ns_for_file 
    { my($base)= @_; 
    my %ns; 
    XML::Twig->new(start_tag_handlers 
     # get namespace declarations from the root and bail 
     => { 'level(0)' => sub { %ns= ns_for_tag($_); 
           $_[0]->finish_now(); 
          } 
     }, 
       ) 
      ->parsefile($base); 
    return %ns; 
    } 

# get all namespace declarations from the root element 
sub ns_for_tag 
    { my($e)= @_; 
    return map { $_ => $e->att($_) if m{^xmlns:} } $e->att_names; 
    } 

sub add_ns 
    { my($file, %ns)= @_; 
    XML::Twig->new(start_tag_handlers => { 'level(0)' => sub { $_->set_att(%ns); } }, 
        twig_handlers => { _all_ => sub { $_->flush; } }, 
        keep_spaces => 1, 
        ) 
       ->parsefile_inplace($file); 

}

+0

我使用libxml2 ...或者實際上是「R」(統計語言)中的libxml2的包裝。如果拆分文件可以被libxml2解析,那將非常好。並感謝這個偉大的工具! – Chris

+0

謝謝,現在測試。當我在原始文件上運行grep xmlns時,我看到5個不同的xmlns:xx =「abc123」,是不是你所說的前綴只聲明過一次? 5箇中的每一個都只列出了onec。 – Chris

+0

是否都是根元素上的命名空間聲明? – mirod