personalt
personalt

Reputation: 850

XML::LibXML findvalue for an attribute with a namespace prefix

I am having some issues using XML::LibXML with namespaces. I have parsed files with namespaces before but this one is a bit different because it is defined with xlmns:abc rather then just xlmns.

I can't extract the 893 value of abc:id from this element

<element name='THEFIELD' type='string' abc:id='893' minOccurs='0' maxOccurs='1'>

Sample data

<schema
    xmlns:abc="http://www.example.com/schemas/abc"
    targetNamespace="http://example.com/schemas/product"
    elementFormDefault="qualified">

  <TheType name='MyName'>
    <sequence>
      <element name='THEFIELD' type='string' abc:id='893' minOccurs='0' maxOccurs='1'>
        <annotation><documentation>Identifier - Realtime</documentation></annotation>
      </element>

My code returns all values correctly (the name and type attributes) but not abc:id

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

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

my $filename = '/schema.xml';
my $dom = XML::LibXML->load_xml( location => $filename );

my $xpc = XML::LibXML::XPathContext->new( $dom );
$xpc->registerNs( 'ns', 'abc:http://www.example.com/schemas/abc' );

foreach my $title ( $xpc->findnodes( '//schema' ) ) {

    foreach my $title ( $xpc->findnodes( '//TheType[@name="MyName"]/sequence/element' ) ) {

        say $title->findvalue( './@name' ), '|', $title->findvalue( '??????' ), '|', $title->findvalue( './@type' );
    }
}

My thoughts are

I tried many things here including things like ns:/@id to *[local-name()="id"]

Upvotes: 0

Views: 696

Answers (1)

choroba
choroba

Reputation: 241858

XML::LibXML::XPathContext doesn't have to be used (in the recent years), it's loaded with XML::LibXML.

The correct usage of the registerNs function is to give it a prefix and URI.

Using the same variable for a nested loop makes no sense, especially if you don't use the outer variable anywhere.

You can use join to avoid repeating the call to findvalue.

#!/usr/bin/perl
use strict;
use warnings;
use feature qw{ say };

use XML::LibXML;

my $filename = shift;
my $dom = 'XML::LibXML'->load_xml(location => $filename);

my $xpc = 'XML::LibXML::XPathContext'->new($dom);
$xpc->registerNs(abc => 'http://www.example.com/schemas/abc');

for my $title ($xpc->findnodes('//TheType[@name="MyName"]/sequence/element')) {
    say join '|', map $title->findvalue($_), '@name', '@abc:id', '@type';
}

Upvotes: 4

Related Questions