Обращение XML-узлов в Perl - PullRequest
0 голосов
/ 22 марта 2012

Мне нужно изменить порядок дочерних узлов в родительском узле.Это xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">

<tv source-info-name="BDS" generator-info-name="mc2xml" generator-    info-url="mailto:mc2xml@gmail.com">
<channel id="I2.751784.microsoft.com">
    <display-name>2 1Xtra BBC</display-name>
    <display-name>2</display-name>
    <display-name>1Xtra BBC</display-name>
    <display-name>BBC R1X</display-name>
</channel>

Программа, в которую я передаю этот xml, принимает в качестве имени только первый узел display-name, что раздражает, потому что тогда эти элементы организуются по этому числу.1006 * Итак, я хочу, чтобы самый последний узел появился первым.

Я использую этот скрипт для извлечения узлов channel.Это часть кода, которая объединяет 2 XML.Но я застрял оттуда на:

foreach my $chan (  $t2->findnodes( '//channel' ) ) {
    $root->insertAfter( $chan, $last_chan );
    $last_chan = $chan;
}

Ответы [ 2 ]

1 голос
/ 22 марта 2012

Этот пример показывает возможное решение.

use strict;
use warnings;

use XML::LibXML;

my $xml = XML::LibXML->load_xml(string => <<'END');
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">

<tv source-info-name="BDS" generator-info-name="mc2xml" generator-info-url="mailto:mc2xml@gmail.com">
<channel id="I2.751784.microsoft.com">
    <display-name>2 1Xtra BBC</display-name>
    <display-name>2</display-name>
    <display-name>1Xtra BBC</display-name>
    <display-name>BBC R1X</display-name>
</channel>
</tv>
END

for my $chan ($xml->findnodes("/tv/channel")) {
  $chan->appendChild($_) for reverse $chan->childNodes;
}

print $xml->toString(1);

вывод

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv source-info-name="BDS" generator-info-name="mc2xml" generator-info-url="mailto:mc2xml@gmail.com">
<channel id="I2.751784.microsoft.com">
<display-name>BBC R1X</display-name>
    <display-name>1Xtra BBC</display-name>
    <display-name>2</display-name>
    <display-name>2 1Xtra BBC</display-name>
    </channel>
</tv>

РЕДАКТИРОВАНИЕ

Я неправильно понял ваше требование и подумал, что вы хотите, чтобы <display-name> элементы менялись внутри каждого <channel>.Вот ядро ​​кода для обращения элементов <channel> в <tv>.

my @channels = $xml->find('/tv/channel');
my $tv = $channels[0]->parentNode;
$tv->appendChild($_) for reverse @channels;

Теперь я думаю, что был прав с первого раза.Сделай свой выбор!

0 голосов
/ 22 марта 2012
for my $channel_node ($root->findnodes('//channel')) {
   for my $child_node (reverse $channel_node->childNodes()) {
      $channel_node->removeChild($child_node);
      $channel_node->appendChild($child_node);
   }
}

appendChild говорит, что не будет работать, если узел уже является дочерним по отношению к родительскому элементу, поэтому используется removeChild.Но тестирование показывает, что removeChild на самом деле не нужно.

...