在拆分或grep后保留XML名称空间
我有一个巨大的xml文件(几GB),我可以用xml_split分割它,或者用xml_grep提取相关的子节点。如果我试图读取整个XML,内存就会耗尽 但是,当我试图解析一个被拆分的文件或grep:ed文件时,我无数次地收到错误“yy上的名称空间前缀xx未定义” 有没有办法将名称空间定义从原始文件复制到拆分文件或grep:ed文件?还是我误解了错误 我对XML非常陌生,我发现XML::TWIG很有用。下面是我使用的grep命令:在拆分或grep后保留XML名称空间,xml,perl,Xml,Perl,我有一个巨大的xml文件(几GB),我可以用xml_split分割它,或者用xml_grep提取相关的子节点。如果我试图读取整个XML,内存就会耗尽 但是,当我试图解析一个被拆分的文件或grep:ed文件时,我无数次地收到错误“yy上的名称空间前缀xx未定义” 有没有办法将名称空间定义从原始文件复制到拆分文件或grep:ed文件?还是我误解了错误 我对XML非常陌生,我发现XML::TWIG很有用。下面是我使用的grep命令: xml_grep --root 'SubInformation' -
xml_grep --root 'SubInformation' --cond 'SubInformationName[string()="Blah"]' Infile.xml > Outfile.xml
要处理大型XML文件,还可以使用pull解析器。请参阅。您使用哪个工具来解析拆分结果(或grep)
xmllint
(来自libxml2
)抱怨,但xmlwf
(来自expat
)没有抱怨。所以我认为任何基于expat的工具都可以使用XML,但不能使用基于libxml2的工具
看起来xml\u split
和xml\u grep
可以声明名称空间。至少这应该是一种选择。我来看看
同时,这里有一种快速、肮脏的方法来对使用xml\u grep
得到的结果进行后处理:
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\u split
的结果想出一种通用的方法。我是否可以假定名称空间声明不是太复杂(即前缀只声明一次)
编辑:在infle.xml上运行xml\u split
后,可以将名称空间声明添加到由xml\u split
生成的文件中,称之为add\ns infle
:
#!/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);
}我使用libxml2。。。或者实际上是“R”(统计语言)中libxml2的包装器。如果libxml2能够解析分割的文件,那就太好了。顺便说一句,谢谢你的好工具!谢谢,现在测试。当我在原始文件上运行grep xmlns时,我看到了5个不同的xmlns:xx=“abc123”,这就是您仅声明一次前缀的引用吗?这5个元素中的每一个都只在onec中列出。名称空间声明都在根元素上吗?我为
xml\u split
添加了一个解决方案。它唯一的假设是名称空间声明位于原始文档的根上。如果不是这样的话,让我知道,它会更复杂一点(我想会慢得多)