2014-10-30 4 views
1

Я пробовал несколько разных методов анализа XML-документов. Мне нужно найти узел в документе с атрибутом x, а затем переместить этот узел со своими дочерними элементами на другой родительский узел.Как перемещать узел в XML-данных с помощью Perl

У меня был некоторый успех, используя XML::LibXML для определения местонахождения узла и возможности повторения его дочерних элементов, но я застрял в том, как переместить его в другой родитель.

Использование $node->cloneNode(1) выглядит многообещающим, но я не могу найти хороших примеров его использования.

Это исходные данные XML

<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
     <address ip="10.0.0.103">Private</address> 
     <address ip="10.0.1.103">Private</address> 
    </server> 
    </old> 
    <new> 
    </new>   
</config> 

и это результат я хотел бы

<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
     <address ip="10.0.0.103">Private</address> 
     <address ip="10.0.1.103">Private</address> 
    </server> 
    </new>   
</config> 
+0

Что вы имеете в виду * "узел с 'х' атрибут" *? Вы говорите, что хотите переместить элемент 'server' с атрибутом' name' 'kalahari'? – Borodin

+0

Пожалуйста, продемонстрируйте код Perl, который вы пробовали – Borodin

+0

Отлично. Это потрясающе. Спасибо вам обоим! Да, Borodin, как в этом примере, соответствует некоторому атрибуту, например name или ip. У меня нет кода для перемещения, поскольку я понятия не имел, с чего начать:/Я могу определенно работать с этим. Еще раз спасибо! –

ответ

2

Использование XML::LibXML:

use strict; 
use warnings; 

use XML::LibXML; 

my $xml = XML::LibXML->load_xml(IO => \*DATA); 

my ($new) = $xml->findnodes('//new'); 

for my $linux ($xml->findnodes('//old/server[@osname="linux"]')) { 
    $linux->unbindNode();   # Remove from Parent (done automatically when added elsewhere without cloning) 
    $new->addChild($linux); 
} 

print $xml; 

__DATA__ 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
     <server name="sahara" osname="solaris" osversion="2.6"> 
      <address ip="10.0.0.101">Private</address> 
      <address ip="10.0.1.101">Private</address> 
     </server> 
     <server name="gobi" osname="irix" osversion="6.5"> 
      <address ip="10.0.0.102">Private</address> 
     </server> 
     <server name="kalahari" osname="linux" osversion="2.0.34"> 
      <address ip="10.0.0.103">Private</address> 
      <address ip="10.0.1.103">Private</address> 
     </server> 
    </old> 
    <new> 
    </new>  
</config> 

Выходы:

<?xml version="1.0"?> 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
     <server name="sahara" osname="solaris" osversion="2.6"> 
      <address ip="10.0.0.101">Private</address> 
      <address ip="10.0.1.101">Private</address> 
     </server> 
     <server name="gobi" osname="irix" osversion="6.5"> 
      <address ip="10.0.0.102">Private</address> 
     </server> 

    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
      <address ip="10.0.0.103">Private</address> 
      <address ip="10.0.1.103">Private</address> 
     </server></new>  
</config> 
+0

Нет необходимости 'unbindNode' – Borodin

+0

Aye. Я заметил, что после позиционирования, но решил, что все еще полезно продемонстрировать, как явно удалить из родителя. Добавлен комментарий к явным – Miller

+0

Вопрос: Каково значение 'my()' при объявлении: 'my ($ new) = $ xml-> findnodes ('// new');' в отличие от просто 'my $ new'? –

1

Все, что вам нужно сделать, это найти как дочерний узел, так и родительский элемент, и переместить его в новый родитель с вызовом appendChild.

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

Я не знаю, как лучше уговорить XML::LibXML для получения данных с отличным отступом. Лучшее, что я нашел, это включить no_blanks и использовать ненулевой параметр до toString, но, как вы можете видеть, это далеко не идеальный.

use strict; 
use warnings; 

use XML::LibXML; 

my $xml = XML::LibXML->load_xml(location => 'config.xml', no_blanks => 1); 

my ($kalahari) = $xml->findnodes('/config/old/server[@name="kalahari"]'); 

my ($new) = $xml->findnodes('/config/new'); 

$new->appendChild($kalahari); 

print $xml->toString(1); 

выход

<?xml version="1.0"?> 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"><address ip="10.0.0.103">Private</address><address ip="10.0.1.103">Private</address></server></new> 
</config> 
+1

'no_blanks' - это в основном хак. Для получения хорошо отформатированного вывода, 'XML :: LibXML :: PrettyPrint', вероятно, лучший выбор. – nwellnhof

+0

@nwellnhof: Я посмотрел на это, но я не вижу причин, по которым 'XML :: LibXML' не сможет сделать это сам по себе. Мне не нравится, что есть целый другой модуль, который эффективно работает. Кстати, ссылка есть ['XML :: LibXML :: PrettyPrint'] (https://metacpan.org/module/XML::LibXML::PrettyPrint) – Borodin

Смежные вопросы