1

我是 Perl 新手,这是我的第一个 Perl 程序,我有一个 XML 文件,我需要使用某种类型的自动化进行编辑:

<Host appBase="webapps"
        unpackWARs="true"
        autoDeploy="true"
        deployOnStartup="true"
        deployXML="true"
        name="localhost"
        xmlValidation="false"
        xmlNamespaceAware="false">
</Host>

目标是在 XML 文件中搜索此节并获取用户输入并将其添加xmlNamespaceAware=false到结束标记之后但之前,以获得将标记添加为子标记的此输出<Alias>

<Host appBase="webapps"
            unpackWARs="true"
            autoDeploy="true"
            deployOnStartup="true"
            deployXML="true"
            name="localhost"
            xmlValidation="false"
            xmlNamespaceAware="false">
            <Alias>HOST.com</Alias>
</Host>
4

2 回答 2

2

这不是一个容易的问题。通过想要保持属性顺序,也许,您没有指定它,其余的格式,您并没有真正将 XML 视为 XML。大多数 XML 解析器都没有为您提供执行所需数据的详细信息。

处理 XML 的软件不应该关心属性顺序或不重要的空白。因此,使用XML::Twig或任何其他方式添加属性应该很简单。

但是,通过想要保持完全相同的属性顺序,您对代码施加了一个约束,从而彻底改变了它。您将离开 XML 领域并将数据视为纯文本。这可能很好而且没什么大不了的,可能您只需要为它编写一个简单的解析器,一个可以让您访问原始格式的解析器。除了输入可能被指定为“XML”并且将来它可能会以会破坏您的代码但不会破坏 XML 解析器的方式发生变化。

好的,现在已经不碍事了,XML::Twig实际上确实让您保持属性顺序 ;--),keep_atts_order在您创建树枝时使用该选项。所以这很容易。

保持格式虽然有点棘手。在您的情况下,对于您提供的有限数据样本,我可以通过对返回元素开始标记的方法进行子类化来使其工作。不过,让它正常工作会复杂得多。

所以这是一个你可以使用的框架

#!/usr/bin/perl

use strict;
use warnings;
use Test::More;

use XML::Twig;

# get the input and the expected result
my( $in, $expected)= do { $/="\n\n"; <DATA>};
chomp $in; chomp $expected;

my $xna= 'false'; # represents the user inpput

my $t= XML::Twig->new( twig_handlers => { Host => sub { $_->set_att( xmlNamespaceAware => $xna); } 
                                        },
                       keep_atts_order => 1,            # the bit you were looking for
                       elt_class => 'XML::Twig::MyElt', # to use the element sub-class 
              )
                ->parse( $in);

is( $t->sprint, $expected, 'one test for now');

done_testing();


package XML::Twig::MyElt;

use XML::Twig;
use base 'XML::Twig::Elt';

sub start_tag
  { my( $elt)= @_;
    if( $elt->tag ne 'Host')
      { return $elt->SUPER::start_tag }
    else
      { return '<' . $elt->tag . ' '
              . join( "\n            ", 
                       map { qq{$_="} . $elt->att( $_) . qq{"} } 
                         keys %{$elt->atts}      # the keys are in the right order
                    )
              . '>';
      }
  }

package main;

__DATA__
<Host appBase="webapps"
            unpackWARs="true"
            autoDeploy="true"
            deployOnStartup="true"
            deployXML="true"
            name="localhost"
            xmlValidation="false">
            **<Alias>HOST.com</Alias>**
</Host>

<Host appBase="webapps"
            unpackWARs="true"
            autoDeploy="true"
            deployOnStartup="true"
            deployXML="true"
            name="localhost"
            xmlValidation="false"
            xmlNamespaceAware="false">
            **<Alias>HOST.com</Alias>**
</Host>

但实际上,保持格式完整是疯狂的。或者如果你喜欢这种挑战就很有趣;--)

于 2012-03-16T05:56:02.223 回答
0

我没有使用过 XML::Twig - 不过我使用过 XML::Simple。如果属性必须保持有序,您可能只需要坚持字符串处理。

use XML::Simple;

my $xml = '<Host appBase="webapps" unpackWARs="true"  autoDeploy="true" deployOnStartup="true" deployXML="true" name="localhost" xmlValidation="false" xmlNamespaceAware="false"></Host>';
my $ref = XMLin($xml);
$ref->{Alias} = { content => 'User Input' };
my $newxml = XMLout($ref, RootName => 'Host');
print $newxml;
于 2012-03-15T19:43:18.897 回答