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