0

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

  • $xpc->registerNs( 'ns', 'abc:http://www.example.com/schemas/abc' ); is wrong

  • Every possibility I tried for the findvalue for abc:id—where the ???? is in the code—was wrong.

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

Borodin
  • 126,100
  • 9
  • 70
  • 144
personalt
  • 810
  • 3
  • 13
  • 26
  • The usage is `$xpc->registerNs('abc', 'http://www.example.com/schemas/abc');`. Then use `abc:id` instead of `id` in the XPaths. – ikegami Dec 07 '17 at 16:54
  • `ns:/@id` should be `@abc:id` and `*[local-name()="id"]` is looking for an *element* with a local name of `id` and will not match attributes. Within both the XML and the Perl code, a namespace is identified by its URI. In your XML the prefix `abc` stands in for that URI, but you may use another name altogether in your Perl (although it would be wise not to). – Borodin Dec 07 '17 at 21:47

1 Answers1

4

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';
}
choroba
  • 231,213
  • 25
  • 204
  • 289