[prev in list] [next in list] [prev in thread] [next in thread] 

List:       perl-xml
Subject:    Re: Namespaces and findnodes() in XML::LibXML
From:       Steve Hay <steve.hay () uk ! radan ! com>
Date:       2003-01-24 17:27:21
[Download RAW message or body]

Bjoern Hoehrmann wrote:

>* Steve Hay wrote:
>  
>
>>I'm trying to retrieve some attribute node values via XPath in 
>>XML::LibXML and keep getting nothing.  The following test program 
>>demonstrates my problem:
>>    
>>
>
>  
>
>>This outputs nothing instead of "1".
>>
>>From previous postings on this list it looks as though the problem is 
>>related to the "xmlns" namespace attribute in the document element. 
>>Sure enough, if I remove that then the program works as expected.
>>
>>However, I'm trying to process thousands of existing XML documents which 
>>all have such an attribute in the document element, so I can't simply 
>>remove this from each file.  How do I achieve what I'm trying to do here?
>>    
>>
>
>You need to setup a prefix for that namespace. This could be done by
>copying the old document to a new one with such prefix like
>
>    my $doc = $parser->parse_string($text);
>    my $tdoc = XML::LibXML::Document->new();
>    my $troot = $tdoc->createElement('html');
>    $troot->setNamespace('http://www.w3.org/1999/xhtml', 'h');
>    $tdoc->setDocumentElement($troot);
>    $troot->appendChild($_->cloneNode(1)) foreach $root->childNodes;
>    $doc = $tdoc;
>  
>
In fact, the following similar idea seems to work, without cloning the 
document:

    use XML::LibXML;

    my $doc = <<'EOT';
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <foo xmlns="http://www.foo.com">
      <bar num="1"/>
    </foo>
    EOT

    my $parser = XML::LibXML->new();
    my $dom_doc = $parser->parse_string($doc);

    my $doc_elt = $dom_doc->documentElement();
    my $nsURI = $doc_elt->namespaceURI();
    $doc_elt->setNamespace($nsURI, 'x');

    my $xpath = "/x:foo/x:bar/attribute::num";
    foreach my $attr ($dom_doc->findnodes($xpath)) {
        print $attr->getValue(), "\n";
    }

However, I sometimes need to change the XML data and then write the file 
back via $dom_doc->toFile(), and the above approach alters the file. 
 For example, the above would output:

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <x:foo xmlns="http://www.foo.com" xmlns:x="http://www.foo.com">
      <bar num="1"/>
    </x:foo>

I tried resetting the prefix before calling toFile() with 
$doc_elt->setNamespace($nsURI); but I still get:

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <foo xmlns="http://www.foo.com" xmlns:x="http://www.foo.com">
      <bar num="1"/>
    </foo>

output.

>A different approach would be to write
>
>  *[local-name()     = "foo" and
>    namespace-uri(.) = "http://www.foo.com"]
>
>instead of 'prefix:foo'.
>
This works better for me.  Just changing the $xpath line in my original 
test program to

    my $xpath = 
qq{/*[local-name()="foo"]/*[local-name()="bar"]/attribute::num};

does the job.  (There is only ever one namespace involved.)

Thanks for the suggestions.

- Steve

_______________________________________________
Perl-XML mailing list
Perl-XML@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic