Perl正则表达式删除XML中的节点

mat*_*ler 0 regex xml perl

我有一个大的(> 2gb)XML文件,看起来大致如下:

<record id="1">
    <a>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </a>
    <b>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </b>
    <c>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </c>
</record>
...
<record id="999999">
    <a>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </a>
    <b>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </b>
    <c>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </c>
</record>
Run Code Online (Sandbox Code Playgroud)

但是,我的实际文件没有每个节点的换行符(尽管在整个过程中随机散布了一些换行符.)

我想使用Perl删除每个节点<b>中的所有 <record>节点,包括它们的后代.

所以 - 我的结果文件看起来像这样:

<record id="1">
    <a>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </a>
    <c>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </c>
</record>
...
<record id="999999">
    <a>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </a>
    <c>
        <detail>blah</detail>
        ....
        <detail>blah</detail>
    </c>
</record>
Run Code Online (Sandbox Code Playgroud)

这是一个重要的注释......正如我所提到的,文件大约是2.4gb.对于较小的文件,我使用XMLReader和PHP来成功解析文件并提取我需要的内容.但是,似乎PHP无法处理这么大的文件(PHP <v.5.6使用32位文件指针).因此,我的目标是使用类似的实用程序sedperl通过剥离我不需要的大块来减少文件.我知道"XML-aware"实用程序更适合这种类型的工作,但我还没有找到一个可以处理这么大的文件...

无论如何,我试过这个(@用作我的分隔符):

perl -pe  's@<b>.*</b>@@sg' input.xml > modified.xml
Run Code Online (Sandbox Code Playgroud)

但这没有用 - 它根本没有删除任何节点.

我确信<b>节点没有任何会破坏模式的属性.

显然 - 我说到这是一个菜鸟,所以我相信我甚至不会接近......

too*_*lic 6

XML :: Twig可用于从大型XML文件中剪切元素,而不必担心元素之间的空白:

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

my $xml = do { local $/; <DATA> };

my $twig = XML::Twig->new(
    twig_handlers => {
        'record/b' => sub { $_->cut() }
    },
    pretty_print => 'indented'
);
$twig->parse($xml);
$twig->print();

__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<top>
    <record id="1">
        <a>
            <detail>blah</detail>
            <detail>blah</detail>
        </a>
        <b>
            <detail>blah</detail>
            <detail>blah</detail>
        </b>
        <c>
            <detail>blah</detail>
            <detail>blah</detail>
        </c>
    </record>
    <record id="999999">
        <a>
            <detail>blah</detail>
            <detail>blah</detail>
        </a>
        <b>
            <detail>blah</detail>
            <detail>blah</detail>
        </b>
        <c>
            <detail>blah</detail>
            <detail>blah</detail>
        </c>
    </record>
</top>
Run Code Online (Sandbox Code Playgroud)

这是输出:

<?xml version="1.0" encoding="UTF-8"?>
<top>
  <record id="1">
    <a>
      <detail>blah</detail>
      <detail>blah</detail>
    </a>
    <c>
      <detail>blah</detail>
      <detail>blah</detail>
    </c>
  </record>
  <record id="999999">
    <a>
      <detail>blah</detail>
      <detail>blah</detail>
    </a>
    <c>
      <detail>blah</detail>
      <detail>blah</detail>
    </c>
  </record>
</top>
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用XML :: Twig附带的xml_grep,我认为(对我来说测试它已经太晚了)`xml_grep -v'record/b'file.xml> new_file.xml`会起作用 (2认同)
  • @miller是的,你正在读取内存中的整个文件,实际上只是在做`XML :: Twig-> new(twig_roots => {'record/b'=> 1},twig_print_outside_roots => 1) - > parsefile(" file.xml")`将输出整个文件(因为'print_outside_roots`,而省略`b`元素).http://xmltwig.org/xmltwig/tutorial/yapc_twig_s4.html教程的第4.5节描述了这一点. (2认同)