过滤文本xml文件

过滤文本xml文件

我有一个很大的(有几十万条记录)XML 文件,我想从中仅过滤特定字段。文件构造示例:

<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   ....
   <E></E>
</B>
<Z></Z>
...
<Y></Y>
<A>

我想过滤此 XML 文件并仅包含 C 和 D 字段中包含的 id 和数据。

如何做到这一点?

答案1

xmlstarlet工具将执行以下操作:

xmlstarlet sel -t -m /A -o ID, -v id -n -o C, -v //C -n -o D, -v //D -n test.xml 

对于根元素 ( -m /A) 下的每个 A,它打印字符串“ID”( -o ID,)、id ( ) 的内容-v id、换行符 ( -n),对于子元素 C ( -v //C) 和 D ( -v //D) 及其各自的标头也是如此。双斜杠是“匹配节点下的任何位置”的 XPath。

使用您的测试文件在我的系统上进行测试的结果是逗号分隔的输出:

ID,123
C,value1
D,value2

如果您不需要标头,请-o <whatever>省略参数。

谢谢本文进行解释。

答案2

为了正确回答这个问题,我们理想地需要一个更好的例子 - 一些有效的xml 是一个好的开始。

另外 - 所需输出的示例。例如,您不需要指明您希望<C><D>元素在生成的 XML 中结束的位置。他们是已经的子级<B>- 您想要保留B还是重新设置父级C以及D根?

然而,一般来说,使用和进行重建XML非常容易。XML::Twigperl

例如像这样:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my @wanted = qw ( C D id );


my %wanted = map { $_ => 1 } @wanted; 

sub delete_unwanted_tags {
   my ( $twig, $element ) = @_;
   my $tag = $element -> tag;
   if ( not $wanted{$tag} ) {
        $element -> delete;
   }
}

my $twig = XML::Twig -> new ( twig_handlers => { _all_ => \&delete_unwanted_tags } );
$twig -> parse ( \*DATA );
$twig -> print;

__DATA__
<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   <E></E>
</B>
<Z></Z>
<Y></Y>
</A>

因为我们没有说“保留<B>”,所以结果是:

<A>
  <id>123</id>
</A>

添加<B>wanted列表:

<A>
  <id>123</id>
  <B>
    <C>value1</C>
    <D>value2</D>
  </B>
</A>

但是,如果您想要做的是 reparentCD进入A

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my @wanted   = qw ( id);
my @reparent = qw ( C D );

#turn the above into hashes, so we can do "if $wanted{$tag}"
my %wanted   = map { $_ => 1 } @wanted;
my %reparent = map { $_ => 1 } @reparent;

sub delete_unwanted_tags {
    my ( $twig, $element ) = @_;
    my $tag = $element->tag;
    if ( not $wanted{$tag} ) {
        $element->delete;
    }
    if ( $reparent{$tag} ) {
        $element->move( 'last_child', $twig->root );
    }
}

my $twig = XML::Twig->new(
    pretty_print  => 'indented_a',
    twig_handlers => { _all_ => \&delete_unwanted_tags }
);
$twig->parse( \*DATA );
$twig->print;

__DATA__
<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   <E></E>
</B>
<Z></Z>
<Y></Y>
</A>

注意 - “twig handler”在结尾每个元素的值(当遇到关闭标记时),这就是为什么它有效 - 我们在完成处理(和删除)之前递归查找C和。DB

这会产生:

<A>
  <id>123</id>
  <C>value1</C>
  <D>value2</D>
</A>

在上面,我使用了__DATA__,\*DATA和 ,parse因为它允许我说明 XML 和技术。您可能应该使用parsefile('my_file.xml')而不是parse(\*DATA).

答案3

使用 ltXML2 工具包(爱丁堡大学)中的 lxgrep,例如

$ lxgrep -w A '(id|C|D)' test.xml
<A>
<id>123</id>
<C>value1</C>
<D>value2</D>
</A>

使用这些类型的工具是远的比自己动手更快、更可靠。


XML 常见问题解答:http://xml.silmaril.ie/

相关内容