强制perl XMLin将空标记视为空字符串?

时间:2016-05-15 08:00:35

标签: perl

拥有以下内容:

perl -MXML::LibXML::Simple -MData::Dumper -E '$h=XMLin("<some><bubu>string</bubu></some>");say Dumper $h'

被解析为:

$VAR1 = {
          'bubu' => 'string'
        };

但是

perl -MXML::LibXML::Simple -MData::Dumper -E '$h=XMLin("<some><bubu/></some>"); say Dumper $h'

perl -MXML::LibXML::Simple -MData::Dumper -E '$h=XMLin("<some><bubu></bubu></some>");say Dumper $h'

打印:

$VAR1 = {
          'bubu' => {}
        };

可以获得

$VAR1 = {
          'bubu' => ""
        };

与其他字符串值保持一致吗?

问题背后的真实代码如下:

package Something {
    use Moose;
    has 'bar' => (is => 'ro', isa => 'Str');
    has 'baz' => (is => 'ro', isa => 'Str');
}

use 5.014;
use warnings;
use XML::LibXML::Simple;

my $xml = do {local $/, <DATA>};
my $hr = XMLin($xml);
for my $node( @{$hr->{node}} ) {
    my $obj = Something->new($node);
}
__DATA__
<root>
<node>
    <bar>bar1</bar>
    <baz>baz1</baz>
</node>
<node>
    <bar>bar2</bar>
    <baz/>
</node>
</root>

消亡
Attribute (baz) does not pass the type constraint because: Validation failed for 'Str' with value HASH(0x7f91a4a92450) at /opt/anyenv/envs/plenv/versions/5.24.0/lib/perl5/site_perl/5.24.0/darwin-2level/Moose/Object.pm line 24
    Moose::Object::new('Something', 'HASH(0x7f91a3f3d430)') called at l line 28

因此我需要

  • 将空baz视为{}而不是''
  • 或向包Something添加一些强制,以强制任何空的hashref {}清空字符串''

有什么想法吗?

修改

所以,结果。接受的答案仍然是因为它给出了上述问题的答案。

必须说,在研究了新的(非常复杂的)模块XML::Twig +学习XPath的基础知识3天后,我得到了一个更清晰的解决方案更好的XMLIn解决方案。

XMLIn我需要重新组织got hashref,因为只需要很少的元素并且具有精确定义的结构。 (构造函数可接受)。这样的重组(删除不需要的成员,将更深的hashref值移到arrayrefs等)在perl中是 easy ,但是代码不好并且需要处理上面的问题。

使用XML::Twig(以及此处的2个后续问题)结果比XMLIn更清晰,更易读,更强更短。真的是更好地牺牲一些时间和学习{至少基础知识'XPath等......

3 个答案:

答案 0 :(得分:2)

XML :: LibXML :: Simple似乎没有启用此行为的选项。

XML :: Simple确实如此;将SuppressEmpty设置为空字符串,以将空节点解析为字符串而不是容器:

# perl -MXML::Simple -MData::Dumper \
  -E '$h=XMLin("<some><bubu></bubu></some>", SuppressEmpty => ""); say Dumper $h'

$VAR1 = {
      'bubu' => ''
    };

答案 1 :(得分:1)

您可以使用Data::Find模块遍历哈希,并查找空哈希引用的路径。然后,您可以使用eval将空哈希引用替换为空字符串。这是一个例子:

use strict;
use warnings;

use XML::LibXML::Simple;
use Data::Dumper;
use Data::Find qw/ diter /;

my $xml = <<XML;
<root>
<node>
    <bar>bar1</bar>
    <baz>baz1</baz>
</node>
<node>
    <bar>bar2</bar>
    <baz/>
</node>
</root>
XML

my $h = XMLin($xml);

my $iter = diter $h, sub {
    my $v = shift;

    defined $v and ref($v) eq "HASH" and !(keys %{ $v });
};

while (my $path = $iter->() )
{
    eval "\$h->$path = ''";
}

print Dumper($h);

答案 2 :(得分:1)

首先关闭:Why is XML::Simple "Discouraged"?

XML::Simple不会让事情变得更容易,也会让事情变得更难。我会提倡XML::TwigXML::LibXML。在XML::Twig中获取节点的“值”完全符合您的预期:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;
my $twig = XML::Twig -> parse ( \*DATA ); 

foreach my $node ( $twig -> findnodes('//node/*') ) {
    print $node -> tag, " => \"", $node -> text,"\"\n";
}

__DATA__
<root>
<node>
    <bar>bar1</bar>
    <baz>baz1</baz>
</node>
<node>
    <bar>bar2</bar>
    <baz/>
</node>
</root>

给出:

bar => "bar1"
baz => "baz1"
bar => "bar2"
baz => ""

您可以将其传递给构造函数。