Holly
Holly

Reputation: 333

How to test whether a node contains a namespace

Given the XML snippet bellow how do I tell the difference between

<entry xmlns:georss="...">

with the children

<title>fileName1.jpg</title> 

and

<entry><title type="text">fileName.pdf</title></entry>

I'm using XML::LibXML to loop through the <entry> but this gets each one so the connection between <type> and <link> is lost. I need to test at the <entry> level not the child <type> level

Can you test if entry node has georss namespace?

Something like this gets the value of <type>

foreach my $Entry ($dom->findnodes("//dft:feed/dft:entry")) {

     foreach my $Images ($dom->findnodes("//dft:title[not(\@type='text')]", $Entry)) {
         my $ImageVal = $Images->textContent;
          ####  This finds all the Images

     }

}

XML Snippet

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss">

  <entry xmlns:georss="http://www.georss.org/georss/10" xsi:schemaLocation ="http://www.url1.net/path/ http://www.url2.net/path/11  http://www.url3.net/path/23" >
    <title>fileName1.jpg</title>
    <link href="PathTo/fileName1.jpg" />
  </entry>

  <entry xmlns:georss="http://www.georss.org/georss/10" xsi:schemaLocation ="http://www.url1.net/path/ http://www.url2.net/path/11  http://www.url3.net/path/23" >
    <title>fileName2.jpg</title>
    <link href="PathTo/fileName2.jpg" />
  </entry>

  <entry>
    <title type="text">fileName.pdf</title>
    <link type="application/pdf"  href="PathTo/fileName.pdf" />
  </entry>

</feed>

Upvotes: 0

Views: 190

Answers (1)

Borodin
Borodin

Reputation: 126722

Can you test if entry node has georss namespace?

There is no data in your example that is in the georss namespace. Everything is in the namespace http://www.w3.org/2005/Atom defined in the feed element. The definition xmlns:georss="http://www.georss.org/georss/10" just specifies a namespace prefix georss, but that prefix is never used

You need to create an XML::LibXML::XPathContext object attached to the XML::LibXML document that allows you to specify namespace abbreviations. The code looks like below

Note that I've also had to fix your XML data to include a definition of the xsi namespace, as without it the data is not well-formed

You shouldn't make a habit of adding // at the start of every XPath expression. It forces the XPath engine to unnecessarily search the entire document each time, and an explicit XPath from the root is better practice. It also produces the wrong result with your XPath //dft:title[not(@type='text')] because you're starting the search from the root each time and ignoring the entry context node. Just dft:title[not(@type="text")] is correct

use strict;
use warnings 'all';

use XML::LibXML;
use XML::LibXML::XPathContext;

my $dom = XML::LibXML->load_xml( location => 'feed.xml' );

my $xpc = XML::LibXML::XPathContext->new($dom);
$xpc->registerNs( dft    => 'http://www.w3.org/2005/Atom' );
$xpc->registerNs( georss => 'http://www.georss.org/georss/10' );

for my $entry ($xpc->findnodes('/dft:feed/dft:entry')) {

     for my $images ($xpc->findnodes('dft:title[not(@type="text")]', $entry)) {

         my $image_val = $images->textContent;

         print $image_val, "\n";
     }
}

output

fileName1.jpg
fileName2.jpg

Upvotes: 1

Related Questions