1

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

然后,我比较下面show_id元素中的代码(如在线示例中那样使用数组进行循环,然后$a = $data->{Element1}->{Element2}->{show_id}找到它),看看我是否在哈希表上有匹配项。答对了。我让它工作没有问题。

因此,假设我将中间两个Element2元素的show_id值与ABC11和匹配ABC12。现在我需要编写一个匹配的新文件。所以我尝试这样做XMLout,但我似乎丢失了我读入的整个标签结构。

有什么方法可以读取下面的数据并删除记录ABC10ABC14例如,以相同的格式拧出文件?让我知道这是否有意义。

我也只有在工作中安装XML::SimpleXML::Parser请帮忙!!!

<?xml version="1.0" encoding="ISO-8859-1"?>
<main>
  <Element1>
    <Element2>
        <show/>
        <show_id>ABC10</show_id>
        <staring>
            <show_header>This is a test</show_header>
        </staring>
    </Element2>
        <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>
        <Element2>
            <show/>
            <show_id>ABC14</show_id>
            <staring>
                <show_header>This is a test</show_header>
            </staring>
    </Element2>
  </Element1>
</main>
4

3 回答 3

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>
于 2012-12-06T23:50:13.847 回答
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}.

于 2012-12-06T21:30:58.427 回答
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.
于 2012-12-06T21:31:29.463 回答