XML::LibXML, пространства имен и значение поиска

Я использую XML::LibXML проанализировать XML-документ с пространством имен. Поэтому я использую XML::LibXML::XPathContext в findnodes используя XPath //u:model, Это правильно возвращает 3 узла.

Я сейчас хотел бы использовать findvalue на 3 вернулся XML::LibXML::Element объекты, но я не могу определить рабочий метод /xpath. В качестве альтернативы я перебираю дочерние элементы и сопоставляю их с nodeName напрямую, но это далеко не идеально:

use strict;
use warnings;

use XML::LibXML;
use XML::LibXML::XPathContext;

my $dom = XML::LibXML->load_xml( IO => \*DATA );
my $context = XML::LibXML::XPathContext->new( $dom->documentElement() );
$context->registerNs( 'u' => 'http://www.ca.com/spectrum/restful/schema/response' );

for my $node ( $context->findnodes('//u:model') ) {
    #my $mh = $node->findvalue('mh');
    my ($mh)
        = map { $_->textContent() }
        grep  { $_->nodeName() eq 'mh' } $node->childNodes();

    #my $attr = $node->findvalue('attribute');
    my ($attr)
        = map { $_->textContent() }
        grep  { $_->nodeName() eq 'attribute' } $node->childNodes();

    print "mh = $mh, attr = $attr\n";
}

__DATA__
<root xmlns="http://www.ca.com/spectrum/restful/schema/response">
  <error>EndOfResults</error>
  <throttle>86</throttle>
  <total-models>86</total-models>
  <model-responses>
    <model>
      <mh>0x100540</mh>
      <attribute id="0x1006e">wltvbswfc02</attribute>
    </model>
    <model>
      <mh>0x100c80</mh>
      <attribute id="0x1006e">wltvsutm1ds02</attribute>
    </model>
    <model>
      <mh>0x100c49</mh>
      <attribute id="0x1006e">wltvsdora03</attribute>
    </model>
  </model-responses>
</root>

Выходы:

mh = 0x100540, attr = wltvbswfc02
mh = 0x100c80, attr = wltvsutm1ds02
mh = 0x100c49, attr = wltvsdora03

Есть ли способ использовать закомментированные строки, чтобы найти узлы вместо косвенного метода итерации для детей? Или есть другой способ решения этой проблемы, чтобы получить парные значения?

2 ответа

Решение

Вы не можете использовать $node->findvalue() из-за всего пространства имен по умолчанию. Однако вы можете повторно использовать ваш объект XML::LibXML::XPathContext, чтобы найти нужные значения:

for my $node ( $context->findnodes('//u:model') ) {
   my $mh   = $context->findvalue('u:mh', $node);
   my $attr = $context->findvalue('u:attribute', $node);
   print "mh = $mh, attr = $attr\n";
}

XPath позволяет игнорировать пространства имен с помощью функции local-name:

use XML::LibXML;

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

for my $node ( $dom->findnodes('//*[local-name()="model"]') ) {
    my $mh   = $node->findvalue('*[local-name()="mh"]');
    my $attr = $node->findvalue('*[local-name()="attribute"]');

    print "mh = $mh, attr = $attr\n";
}

Это устраняет необходимость указывать контекст для одного документа пространства имен, как в вопросе.

Ссылка: Re ^ 2: XML:: LibXML и пространства имен

Другие вопросы по тегам