Perl 小树枝-搜索并添加一行

Perl 小树枝-搜索并添加一行,perl,xml-twig,Perl,Xml Twig,我是Perl新手,这是我的第一个Perl程序,我有一个XML文件,需要通过某种类型的自动化进行编辑: <Host appBase="webapps" unpackWARs="true" autoDeploy="true" deployOnStartup="true" deployXML="true" name="localhost" xmlValidation="false" x

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

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

我没有使用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;
使用XML::Simple;
我的$xml='';
my$ref=XMLin($xml);
$ref->{Alias}={content=>'User Input'};
我的$newxml=XMLout($ref,RootName=>'Host');
打印$newxml;

这不是一个容易的问题。如果希望保持属性顺序,并且可能不指定它,其余的格式化,那么就没有真正将XML视为XML。大多数XML解析器都没有提供执行所需的数据的详细信息

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

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

好的,现在这已经不存在了,实际上它允许您保持属性顺序;--),创建细枝时,请使用
keep\u atts\u 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>
#/usr/bin/perl
严格使用;
使用警告;
使用测试::更多;
使用XML::Twig;
#获取输入和预期结果
my($in,$expected)=do{$/=“\n\n”;};
大吃一块;预计将有600万美元;
我的$xna='false'#表示用户输入
my$t=XML::Twig->new(Twig_handlers=>{Host=>sub{$\->set_att(xmlNamespaceAware=>$xna);}
},
保持_atts_order=>1,#您正在寻找的位
elt_class=>XML::Twig::MyElt',#使用元素子类
)
->(单位:元);
是($t->sprint,$expected,'one test for now');
完成测试();
包XML::Twig::MyElt;
使用XML::Twig;
使用基本'XML::Twig::Elt';
子启动标签
{my($elt)=@;
如果($elt->标记ne“主机”)
{return$elt->SUPER::start_tag}
其他的
{返回“”;
}
}
主包装;
__资料__
**HOST.com**
**HOST.com**

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

感谢您的快速响应,但属性需要保持有序。无论如何,它可能会工作,我没有真正测试它。根据,库试图保持属性与接收属性的顺序相同。xml文件中的数据比一节中的数据多,因此无法使用用户输入创建新的xml。我需要搜索该节并以某种方式写入用户输入。当我将您的节加载到$xml中时,我非常简短。您可以通过文件读取或其他方式将整个文档放入该变量中。XMLin将把整个XML文档映射到一个hashref中,您可以做任何您想做的事情。非常确定,您可以将XMLin指向一个文件名,它也可以做到这一点!感谢您在与应用程序所有者交谈后提供的帮助。您是正确的。数据顺序无关紧要。一开始我并不清楚。抱歉,没问题,强迫模块做一些不自然的事情很有趣。我知道有些工具要求属性按特定顺序排列,因此有了
keep\u atts\u 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>