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

I am terribly confused about how I am supposed to make XML::LibXML correctly use name spaces.

I am experimenting with CalDAV and I include two examples from RFC4918

# Example in section 9.1.3 of RFC4918 my $txt1 = '<?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop xmlns:R="http://ns.example.com/boxschema/"> <R:bigbox/> <R:author/> <R:DingALing/> <R:Random/> </D:prop> </D:propfind> '; # Example in section 9.1.5 of RFC4918 my $txt2 = '<?xml version="1.0" encoding="utf-8" ?> <propfind xmlns="DAV:"> <propname/> </propfind> ';

The first example uses 'D' as a prefix for 'DAV' (xmlns:D="DAV:") and the second uses "DAV" as the default name space.

The RFC says of the second example... "[$txt2] demonstrates the use of XML namespace scoping and the default namespace. Since the "xmlns" attribute does not contain a prefix, the namespace applies by default to all enclosed elements.".

The code I am using is:

#!/usr/bin/perl -w use strict; use XML::LibXML; sub doitLX { my $contentRef = shift or die; my $content = $$contentRef; my $xpath = shift or die; $|++; my $parser = XML::LibXML->new(); my $dom = $parser->parse_string($content); my $doc = $dom->documentElement(); my @propfind = (); eval { @propfind = $dom->findnodes($xpath); }; if($@){ print "Failed ".ref($dom)."::findnodes('$xpath') \$@ $@\n"; }else{ print ref($dom)."::findnodes('$xpath') ".scalar(@propfind)." nodes +\n\n"; } eval { @propfind = $doc->findnodes($xpath); }; if($@){ print "Failed ".ref($doc)."::findnodes('$xpath') \$@ $@\n"; }else{ print ref($doc)."::findnodes('$xpath') ".scalar(@propfind)." nodes +\n\n"; } } # Example in section 9.1.3 of RFC4918 my $txt1 = '<?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop xmlns:R="http://ns.example.com/boxschema/"> <R:bigbox/> <R:author/> <R:DingALing/> <R:Random/> </D:prop> </D:propfind> '; # Example in section 9.1.5 of RFC4918 my $txt2 = '<?xml version="1.0" encoding="utf-8" ?> <propfind xmlns="DAV:"> <propname/> </propfind> '; my $xpath1 = '/DAV:propfind/DAV:prop'; my $xpath2 = '/DAV:propfind/DAV:propname'; my $xpath3 = '/D:propfind/D:prop'; my $xpath4 = '/D:propfind/D:propname'; my $xpath5 = '/propfind/prop'; my $xpath6 = '/propfind/propname'; print "\$txt1 \$xpath1 \n"; &doitLX(\$txt1, $xpath1); print "\$txt2 \$xpath2 \n"; &doitLX(\$txt2, $xpath2); print "\$txt1 \$xpath3 \n"; &doitLX(\$txt1, $xpath3); print "\$txt2 \$xpath4 \n"; &doitLX(\$txt2, $xpath4); print "\$txt1 \$xpath5 \n"; &doitLX(\$txt1, $xpath5); print "\$txt2 \$xpath6 \n"; &doitLX(\$txt2, $xpath6);

The output is:

$txt1 $xpath1 Failed XML::LibXML::Document::findnodes('/DAV:propfind/DAV:prop') $@ X +Path error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed Failed XML::LibXML::Element::findnodes('/DAV:propfind/DAV:prop') $@ XP +ath error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed $txt2 $xpath2 Failed XML::LibXML::Document::findnodes('/DAV:propfind/DAV:propname') +$@ XPath error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed Failed XML::LibXML::Element::findnodes('/DAV:propfind/DAV:propname') $ +@ XPath error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed $txt1 $xpath3 XML::LibXML::Document::findnodes('/D:propfind/D:prop') 1 nodes XML::LibXML::Element::findnodes('/D:propfind/D:prop') 1 nodes $txt2 $xpath4 Failed XML::LibXML::Document::findnodes('/D:propfind/D:propname') $@ X +Path error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed Failed XML::LibXML::Element::findnodes('/D:propfind/D:propname') $@ XP +ath error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed $txt1 $xpath5 XML::LibXML::Document::findnodes('/propfind/prop') 0 nodes XML::LibXML::Element::findnodes('/propfind/prop') 0 nodes $txt2 $xpath6 XML::LibXML::Document::findnodes('/propfind/propname') 0 nodes XML::LibXML::Element::findnodes('/propfind/propname') 0 nodes

As far as I can tell the XPats:

my $xpath1 = '/DAV:propfind/DAV:prop'; my $xpath2 = '/DAV:propfind/DAV:propname';

are the correct ones. But I cannot find any documentation that addresses default name spaces. I am lost...

Worik

Replies are listed 'Best First'.
Re: xmlns and XML::LibXML
by Anonymous Monk on Jun 02, 2015 at 02:14 UTC

      I cannot see how to use. XML::LibXML::XPathContext

      The man page says:

      registerNs $xpc->registerNs($prefix, $namespace_uri) Registers namespace $prefix to $namespace_uri.

      But I do not know in advance what the prefix will be.

      <?xml version="1.0" encoding="utf-8" ?> <propfind xmlns="DAV:"> <propname/> </propfind>

      Is valid and

      <?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop xmlns:R="http://ns.example.com/boxschema/"> <R:bigbox/> <R:author/> <R:DingALing/> <R:Random/> </D:prop> </D:propfind>

      is valid too.

      Worik

        But I do not know in advance what the prefix will be.

        You don't need to know it, a prefix is for your xpaths, the namespace is important not the prefix, the prefix is just a shortcut for the namespace

        The person writing xml "registers" a local prefix so they can write their XML with less chars

        The person writing xpath "registers" a local prefix so they can write their xpath with less chars

        Neither person has to use the same prefix to refer to the same namespace

        The prefix used in the XPath doesn't have to match the prefix used in the document. Only the namespaces need to match. Pick a prefix of your liking. See Re^2: xmlns and XML::LibXML.
        I cannot see how to use. XML::LibXML::XPathContext

        Please read the replies carefully. A working piece of example code was given to you an hour before you posted this.

      The key is that the prefixes used in the XPath expression don't have to have anything to do with the prefixes in the XML file. The following works fine on both your example XML inputs.

      my $xml = XML::LibXML->load_xml(string => $txt1); my $xc = XML::LibXML::XPathContext->new($xml); $xc->registerNs('foo', 'DAV:'); print "prop:\n"; print "$_\n" for $xc->findnodes('/foo:propfind/foo:prop'); print "propname:\n"; print "$_\n" for $xc->findnodes('/foo:propfind/foo:propname');
Re: xmlns and XML::LibXML ( local-name() )
by Anonymous Monk on Jun 02, 2015 at 02:37 UTC
      you only need to match on local-name()

      ... which would make code non-namespace-aware and doesn't answer the question "how I am supposed to make XML::LibXML correctly use name spaces" (the answer recommended by XML::LibXML is XML::LibXML::XPathContext). The whole topic has been discussed before, actually in the thread you linked to: Xpath not working.

        ..which would make code non-namespace-aware and doesn't answer the question...The whole topic has been discussed before, actually in the thread you linked to..

        Hmm, I wonder why I linked that threat, its almost like I want folks to read it and make up their own minds

Re: xmlns and XML::LibXML
by locked_user sundialsvc4 (Abbot) on Jun 02, 2015 at 11:48 UTC

    A short quote from WikiPedia might help to clear up the apparent confusion about XML namespaces, what they are and how they are (actually) used:

    A namespace name is a uniform resource identifier (URI).   Typically, the URI chosen for the namespace of a given XML vocabulary describes a resource under the control of the author or organization defining the vocabulary, such as a URL for the author's Web server.   However, the namespace specification does not require nor suggest that the namespace URI be used to retrieve information:   it is simply treated by an XML parser as a string.   [...]   Although the term “namespace URI” is widespread, the W3C Recommendation refers to it as the “namespace name.”

    Upon encountering a namespace reference, any good XML parser will require you to have declared its presence first.   But, it, “the parser,” does not care what that reference is.   “As long as the identifier has previously been made known to me, it is a valid parse.”   Of course, the consumers of an XML document typically do care ... both what namespace-identifier you use, and what namespace-name you associate with that identifier.