XML :: Twig - Поиск и добавление строки - PullRequest
1 голос
/ 15 марта 2012

Я новичок в 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>

Ответы [ 2 ]

2 голосов
/ 16 марта 2012

Это не простая проблема. Желая сохранить порядок атрибутов и, возможно, не указывать его, остальную часть форматирования, вы на самом деле не относитесь к 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>

Но на самом деле сохранение формата без изменений - это безумие. Или весело, если вам нравится такой вызов; -)

0 голосов
/ 15 марта 2012

Я не использовал 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;
...