tags:

views:

487

answers:

2

I need to get the child nodes of a node using XPath as I want to "drill down" into a node. Here's the code I'm trying:

xml_ns = 'Document:http://www.google.com/books/'  

xml_document = XML::Document.file('./test_pages/test.xml')  
book_xpath = '//Document:View/Document:Books'  
book_title_xpath = '//Document:Title'  

xml_document.find(book_xpath, xml_ns).each() { | item |  
    puts item  
    item.find(book_title_xpath, xml_ns).each() { |item2|  
        puts '========================'  
        puts 'name: ' + item2.content().strip()  
    }  
}

And here's an XML fragment

 <Document xmlns="http://www.google.com/books/"&gt;  
     <View>  
      <Books>  
       <Title>pragmatic programming</Title>  
      </Books>  

      <Comics>  
       <Title>x-men</Title>  
      </Comics>  
     </View>  
 </Document>

The first find works find and returns the Books node. However the second find('//Document:Title') return all the Title nodes in the document even though I am only searching in the found nodes.

Why would this happen? I've tired modifying the second XPath, but nothing I've tired works. Any advice?

+1  A: 

The returned xml_document nodes are never broken from the original source. You can always move backwards and forwards, the only difference is that the "pointer" is at the current found node.

What you need to do is change your XPath such that it doesn't do a "full document search": the special // (which is "descendant-or-self") starts at the root and traverses all nodes. Instead, use the following:

book_title_xpath = 'Document:Title'

which will return the first child with the name "Title". If you need to search all subnodes from the Book node, you can do the following:

book_title_xpath = './/Document:Title'

which adds the . and means "start at the current node and search the current node and all descendants".

Abel
thx, thought I had tried that but I guess I hadn't.
Adhamh Findlay
A: 

try

book_title_xpath = 'Title'

Zepplock