2012-03-15 3 views
1

Я новичок в Perl, и это моя первая программа на Perl, у меня есть XML-файл, который нужно изменить с некоторым типом автоматизации:XML :: Twig - Поиск и добавьте строку

<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> 

ответ

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; 
+0

Спасибо за ваш быстрый ответ, но атрибуты должны быть в порядке. – Badboy

+0

В любом случае это может сработать, я его не испытал. Согласно http://search.cpan.org/~grantm/XML-Simple-2.18/lib/XML/Simple.pm, библиотека пытается сохранить атрибуты в том порядке, в котором они были получены. –

+0

В файле xml есть больше данных, чем одна строфа, создание нового xml с помощью пользовательского ввода не является вариантом. Мне нужно найти строфу и как-то написать вход пользователя. – Badboy

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> 

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

+0

Спасибо за вашу помощь после разговора с владельцем приложения, вы правы, порядок данных не имеет значения. Сначала я не знал об этом. Сожалею. – Badboy

+0

не проблема, это было весело, пытаясь принудить модуль делать что-то неестественное.И я знаю, что есть инструменты, которые требуют, чтобы атрибуты приходили в определенном порядке, поэтому опция 'keep_atts_order'. – mirod