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";
}
Это устраняет необходимость указывать контекст для одного документа пространства имен, как в вопросе.