我在TREC format中有一个7GB的XML文档。此文件包含标记DOC
,其中有DOCNO
和TEXT
。
<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
在文件中包含ids列表的DOCNO
:< / p>
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 :(得分:3)
如果您有xml_grep
,我认为perl模块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>
元素,读取下一个元素并提取其文本,使用正则表达式与abc
或ghi
进行比较,并仅打印该部分树匹配的情况。
像以下一样运行:
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>
答案 1 :(得分: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>