在T恤上从XML :: Twig输出Buggy

时间:2016-02-25 13:39:17

标签: xml perl xml-parsing xml-twig

我正在尝试将一个xml文件拆分成多个格式正确的片段,并且an ancient PerlMonks solution正在寻找我正在寻找的XML :: Twig的帮助,它会吐入Tee ...至少简单的数据输入。

如果我通过重新组合节点以过滤到父节点来使数据结构稍微复杂化,则第二个文件格式不正确:父节点缺少其开始标记。我很遗憾找不到原因。

SSCCE(与初始示例的区别在于包含<thing_list>的{​​{1}}:

<thing>

虽然第一个use XML::Twig; use IO::Tee; use feature 'say'; open my $frufile, '>', 'fruit.xml' or die "fruit $!"; open my $vegfile, '>', 'veg.xml' or die "veg $!"; my $tee = IO::Tee->new($frufile, $vegfile); select $tee; my $twig=XML::Twig->new( twig_handlers => { thing => \&magic, _default_ => sub { say STDOUT '_default_ for '.$_->name; $_[0]->flush($tee); #default filehandle = tee 1; }, }, pretty_print => 'indented', empty_tags => 'normal', ); $twig->parse( *DATA ); sub magic { my ($thing, $element) = @_; say STDOUT "magic for ". $element->{att}{type}; for ($element->{att}{type}) { if (/fruit/) { $thing->flush($frufile); } elsif (/vegetable/) { $thing->flush($vegfile); } else { $thing->purge; } } 1; } __DATA__ <batch> <header> <foo>1</foo> <bar>2</bar> <baz>3</baz> </header> <thing_list> <thing type="fruit" >Im an apple!</thing> <thing type="city" >Toronto</thing> <thing type="vegetable" >Im a carrot!</thing> <thing type="city" >Melrose</thing> <thing type="vegetable" >Im a potato!</thing> <thing type="fruit" >Im a pear!</thing> <thing type="vegetable" >Im a pickle!</thing> <thing type="city" >Patna</thing> <thing type="fruit" >Im a banana!</thing> <thing type="vegetable" >Im an eggplant!</thing> <thing type="city" >Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhenuakitanatahu</thing> </thing_list> <trailer> <chrzaszcz>A</chrzaszcz> <zdzblo>B</zdzblo> </trailer> </batch> 还可以:

fruit.xml

<batch> <header> <foo>1</foo> <bar>2</bar> <baz>3</baz> </header> <thing_list> <thing type="fruit">Im an apple!</thing> <thing type="fruit">Im a pear!</thing> <thing type="fruit">Im a banana!</thing> </thing_list> <trailer> <chrzaszcz>A</chrzaszcz> <zdzblo>B</zdzblo> </trailer> </batch> 缺少veg.xml

的开头标记
<thing_list>

我还注意到,如果我将<batch> <header> <foo>1</foo> <bar>2</bar> <baz>3</baz> </header> <thing type="vegetable">Im a carrot!</thing> <thing type="vegetable">Im a potato!</thing> <thing type="vegetable">Im a pickle!</thing> <thing type="vegetable">Im an eggplant!</thing> </thing_list> <trailer> <chrzaszcz>A</chrzaszcz> <zdzblo>B</zdzblo> </trailer> </batch> 标记注释到数据中,那么<thing_list>中的开头标记对应的注释也会丢失,但不会来自veg.xml

我似乎明白第一条评论是在处理第一个fruit.xml时发生的,第二条评论应该在处理文件的其余部分时从<thing>处理程序处理。但我不明白,_default_未被评论时是否相同。

WFIW,我在Windows 7机顶盒上使用Strawberry的Perl 5.20.1

1 个答案:

答案 0 :(得分:3)

哇,哇,我感到惊讶,它的效果和它一样好!

第一次到达$thing->flush($frufile);时,它会打印尚未刷新的所有内容。如果您之前没有尝试解决此问题,则会输出:

<batch>
  <header>
    <foo>1</foo>
    <bar>2</bar>
    <baz>3</baz>
  </header>
  <thing_list>
    <thing type="fruit">Im an apple!</thing>

尝试后,会打印

  <thing_list>
    <thing type="fruit">Im an apple!</thing>

随后您拨打magic<thing_list>以及之前的所有内容都已打印出来,因此无法再次打印。

不要混合输出手柄!如果要生成两个文件,请处理模板两次。 (并摆脱那个_default_枝条处理程序。)

也就是说,从twig_handlers切换到twig_roots(这对大型文档来说更好)似乎有效:

my $twig = XML::Twig->new(
    twig_roots => {
        'thing_list/thing' => sub {
            my ($t, $element) = @_;
            for ($element->{att}{type}) {
                if (/fruit/) {
                    $t->flush($frufile);
                } elsif (/vegetable/) {
                    $t->flush($vegfile);
                } else {
                    $t->purge;
                }
            }
        },
    },
    twig_print_outside_roots => 1,
    pretty_print => 'indented',
    empty_tags => 'normal',
);

使用风险自负:)