使用Perl XML :: Simple读取,删除一些记录并编写相同的XML文件

时间:2012-12-06 20:48:26

标签: xml perl

今天我一直在努力解决这个问题。尝试读取下面的XML文件(我很快就输入了)。我有一个show_id代码的CSV文件。所以我读了它们并将它们放入哈希。然后我使用XML::Simple读取XML文件。

然后我比较了元素中的show_id代码(在在线示例中完成了一个数组的循环,然后在$a = $data->{Element1}->{Element2}->{show_id}找到了它),看看我是否匹配了哈希表。答对了。我没有问题就可以了。

因此,假设我将中间两个Element2元素与show_idABC11的{​​{1}}值进行匹配。现在我需要写一个匹配的新文件。所以我尝试了ABC12,我似乎失去了我读过的整个标签结构。

有没有办法读取下面的数据并删除记录XMLoutABC10,并以相同的格式删除文件?如果这是有道理的,请告诉我。

此外,我只在工作时安装了ABC14XML::Simple。请帮助!!!

XML::Parser

3 个答案:

答案 0 :(得分:2)

如果你能得到 XML::Twig 已安装,这是您可能更喜欢的解决方案。

use strict;
use warnings;

use XML::Twig;

my %keep = (
  ABC11 => 1,
  ABC12 => 1,
);

my $twig = XML::Twig->new(
  keep_spaces => 1,
  twig_handlers => { Element2 => \&Element2 }
);  

$twig->parsefile('data.xml');
$twig->print;

sub Element2 {
  my ($twig, $elem) = @_;
  my $show_id = $elem->first_child_text('show_id');
  $elem->delete unless $keep{$show_id};
}

或者如果您愿意 XML::LibXML 那么这将有效

use strict;
use warnings;

use XML::LibXML;

my %keep = (
  ABC11 => 1,
  ABC12 => 1,
);

my $xml = XML::LibXML->load_xml(location => 'data.xml');

for my $elem2 ($xml->findnodes('//Element2')) {
  my $show_id = $elem2->find('show_id');
  $elem2->parentNode->removeChild($elem2) unless $keep{$show_id};
}

print $xml->toString;

这些程序的输出完全相同。

<强>输出

<?xml version="1.0" encoding="ISO-8859-1"?>
<main>
  <Element1>

        <Element2>
            <show/>
            <show_id>ABC11</show_id>
            <staring>
                <show_header>This is a test</show_header>
            </staring>
    </Element2>
        <Element2>
            <show/>
            <show_id>ABC12</show_id>
            <staring>
                <show_header>This is a test</show_header>
            </staring>
    </Element2>

  </Element1>
</main>

答案 1 :(得分:1)

首先,摆脱废弃的元素:

$data->{Element1}{Element2} = [
  grep { $_->{show_id} =~ /^ABC1[12]$/ } @{$data->{Element1}{Element2}}
];

然后,以XML格式写出来。 (对于NoAttr => 1,哈希表示为嵌套元素而不是属性。)

print XMLout($data, NoAttr => 1, RootName => "main");

您可以将KeepRoot => 1传递给XMLin和XMLout来处理根元素(“main”)而不是RootName => 1。如果您这样做,请使用$data->{main}{Element1}{Element2}

答案 2 :(得分:1)

如果你想要同样的东西出来,不要使用XML :: Simple。以下是使用XML::Rules的解决方案:

use strict;
use warnings;

use XML::Rules;

my @keep_these = qw(
  ABC11
  ABC12
);
my %keep; $keep{$_}++ for @keep_these;

my @rules = (
  Element2 => sub {
    my $id = $_[1]->{show_id}{_content};
    return unless $keep{$id};
    return $_[0] => $_[1];
  },
);
my $p = XML::Rules->new(
  style => 'filter',
  rules => \@rules,
  stripspaces => 3,
);

$p->filter(\*DATA, \*STDOUT);

__END__
<?xml version="1.0" encoding="ISO-8859-1"?>
<main>
  <Element1>
    <Element2>
etc.