Re: XML::LibXML XPath fails to find xmlns:xml="http://www.w3.org/XML/1998/namespace"
Petr Pajas <[email protected]>
| Newsgroups | gmane.comp.lang.perl.xml |
|---|---|
| Organization | UFAL MFF UK |
| Message-ID | <[email protected]> |
Hi Emmanuel,
you are right, but is it worth fixing? The namespace:: axis is problematic and
not fully implemented even in libxml2 itself. The problem is that namespace
nodes are in libxml2 represented by a very simple structure (compared to
other nodes); unlike for instance ordinary attribute nodes, they do not know
their owner element (e.g. namespace::*/parent::* won't work), sibling
attributes, etc. Also their life cycle in libxml2 is different and quite
complicated (a NS node can be attached to no element, yet still there may be
elements refering to it as their namespace). For this reason, XML::LibXML's
memory management is quite elementary for NS nodes compared to other nodes.
We currently create a copy of xmlNs struct every time we expose a namespace
to Perl. It is simple but safe.
What libxml2 does when it needs to instantiate a NS node for the 'xml' prefix
is that it creates the xmlNs struct by hand (avoiding the xmlNewNs
constructor):
xmlNsPtr ns;
ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
if (ns == NULL) {
xmlTreeErrMemory(
"allocating the XML namespace");
return (NULL);
}
memset(ns, 0, sizeof(xmlNs));
ns->type = XML_LOCAL_NAMESPACE;
ns->href = xmlStrdup(XML_XML_NAMESPACE);
ns->prefix = xmlStrdup((const xmlChar *)"xml");
I could of course do the same, but I don't feel very comfortable adding such
an unencapsulated code to XML::LibXML, but I'm willing to if you insist.
If you think you have a use case for which it is worth fixing, you can file a
bug on rt.cpan.org and I'll take care of it while working on a next release.
Best,
-- Petr
On Monday 29 December 2008 10:58:27 Emmanuel Rodriguez wrote:
> Hi,
>
> I have found a strange behavior of XML::LibXML when handling the results
> of an XPath search that includes namespaces using the prefix 'xml'.
>
> If a document defines the following namespace:
> xmlns:xml="http://www.w3.org/XML/1998/namespace" then the XPath
> expression '//namespace::*' will not return that namespace. I have
> attached a test case that shows the problem. The test may seem strange
> as there are more namespaces returned than declared but this is what
> xmllint --shell returns!
>
> I think that this "bug" is a border line case as the prefix 'xml' is
> reserved in the XML specification. Although, I think that it should be
> fine to use xmlns:xml="http://www.w3.org/XML/1998/namespace" in a
> document [See http://www.stylusstudio.com/xmldev/200201/post91720.html].
>
> I tried to use xmllint --shell and a sample C program using the XPath
> API of libxml and they both work fine. So I made some investigation and
> found out that the XS method XML::LibXML::Node::_findnodes() is removing
> the nodes involuntarily through this code:
>
> if (tnode->type == XML_NAMESPACE_DECL) {
> xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
> if ( newns != NULL ) {
> element = NEWSV(0,0);
> cls = PmmNodeTypeName( tnode );
> element = sv_setref_pv( element,
> (const char *)cls,
> newns
> );
> }
> else {
> continue;
> }
> }
>
> The call to xmlCopyNamespace() is the source of the problem.
> xmlCopyNamespace() uses xmlNewNs() to create a new node, but xmlNewNs()
> has the following assertion:
>
> if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
> return(NULL);
>
> That's why findnodes() is discarding some results, xmlNewNs() refuses to
> create a namespace node having the prefix "xml".
>
> PS: The same should be true for XML::LibXML::XPathContext::_findnodes().
>
> Emmanuel Rodriguez.
_______________________________________________
Perl-XML mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs