Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

XML::LibXML::Element appendChild/addChild not inheriting namespace?

by szr (Scribe)
on Dec 31, 2015 at 18:39 UTC ( [id://1151607]=perlquestion: print w/replies, xml ) Need Help??

szr has asked for the wisdom of the Perl Monks concerning the following question:

I feel there is something I'm missing in regards to namespace inheritance in XML::LibXML. Please consider the following:
<?xml version="1.0"?> <root xmlns:foo="http://foo"><parent><foo:child/></parent></root>
Element foo:child is valid without a xmlns:foo="http://foo" attribute since that appears further up the tree, in the root node. What I don't quite understand is the behavior of addChild or appendChild of XML::LibXML::Node which doesn't seem to realize that prefix is associated with a namespace further up the tree (in the root node) and doesn't properly split foo:child.
use strict; use warnings; use XML::LibXML; my $d = XML::LibXML::Document->new; $d->setDocumentElement( my $r = $d->createElement( q{root} ) ); $r->setNamespace( q{http://foo}, q{foo}, 0 ); my $p = $r->addChild( $d->createElement( q{parent} ) ); my $c = $p->addChild( $d->createElement( q{foo:child} ) ); printf qq{child->prefix=%s, child->localname=%s\n}, $c->prefix, $c->lo +calname;
Which yields: child->prefix=, child->localname=foo:child
When I would have expected: child->prefix=foo, child->localname=child

I know createElementNS can be used, but that requires one to know what NS to pass rather than being able to rely on inheritance. What is even stranger is inheritance actually appears to work with attributes. If I add the following to the code above:
$c->setAttribute( q{foo:abc}, q{123} ); my $an = $c->getAttributeNode( q{foo:abc} ); printf qq{an->prefix=%s, an->name=%s\n}, $an->prefix, $an->name;
I get this: an->prefix=foo, an->name=abc

Also note the lack of using setAttributeNS method, as this is about inheritance, rather than manually specifying the namespace uri each time an attribute is added.

So why doesn't this seem to work for elements? Maybe I'm really missing something, probably fairly obvious, as it seems this should be trivial.

Thanks.

Replies are listed 'Best First'.
Re: XML::LibXML::Element appendChild/addChild not inheriting namespace?
by choroba (Cardinal) on Dec 31, 2015 at 19:24 UTC
    If you want to add a new child with a namespace, use addNewChild:
    my $c = $p->addNewChild('http://foo', 'child');

    If you need to use the prefix and inheritance, combine it with lookupNamespaceURI:

    my $c = $p->addNewChild($p->lookupNamespaceURI('foo'), 'child');
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Thank you for the reply. Yes, your method appears to work.

      One thing is still bugging me though, in regards to $child->localname yielding foo:child, which doesn't seem to be XML 1.0 compliant, as a colon usually isn't allowed in the localname or prefix parts, as it's reserved as the separator, yet localname contains it in my original test case above.

      Would this constitute a bug, or is this desired behavior somehow?
        I think the problem is already in createElement which accepts 'foo:child' without checking the prefix. I'm not sure whether it's a problem on the Perl or underlying C side, though.
        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1151607]
Front-paged by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2024-04-25 23:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found