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パーサーではなく、コードを壊すような方法で将来変更される可能性があります。

OK、これは邪魔にならないので、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 に答える