13

I'm trying to access the content of an element based on the value of an attribute. With PHP SimpleXML. I've got the following XML setup:

<DocSum> 
    <Id>21242919</Id> 
    <Item Name="Author" Type="String">Nguyen T</Item>
    <Item Name="Title" Type="String">[Hemoptysis and spontaneous rupture of a primary renal angiosarcoma: a case report.]</Item>
</DocSum>
<DocSum> 
    <Id>21242919</Id> 
    <Item Name="Author" Type="String">Oliveira GC</Item>
    <Item Name="Title" Type="String">Disclosing ambiguous gene aliases by automatic literature profiling.</Item>
</DocSum>
<DocSum> 
    <Id>21242919</Id> 
    <Item Name="Author" Type="String">Vanderwall DE</Item>
    <Item Name="Title" Type="String">Metformin and digestive disorders.</Item>
</DocSum>

These are books. In this case I'm trying to get the title. What I have so far is this:

$xml = simplexml_load_file(url);
$docs = $xml->DocSum;
foreach($docs as $book){
        // Each book individual
}

Where the comment is I tried a lot of things.

Bob
  • 1,066
  • 2
  • 14
  • 28
  • @Gordon: I think this is asking what to use, not how to use it. –  Jan 22 '11 at 18:29
  • @Alejandro quoting the OP in that question "I want to select the nodes based on the date" where date is an attribute of an element. Bob asks how to get the "content of an element based on the value of an attribute". There is no difference to me. – Gordon Jan 22 '11 at 18:36
  • @Gordon: OP also wrote *"and I am using this XQuery and XPath to select the nodes"* and explicitly ask for XPath and XQuery in title. –  Jan 22 '11 at 18:43
  • @Alejandro the accepted solution is an XPath though and given that there is no [official XQuery support](http://stackoverflow.com/questions/2211743/execute-a-xquery-with-php/2212356) in any of the native PHP XML extensions … :) – Gordon Jan 22 '11 at 18:47

2 Answers2

21

This XPath query on the SimpleXML object will return all DocSum nodes that have an Item child with value "Author" in the Name attribute and value "Olivera GC" in the text node:

$nodes = $xml->xpath('//DocSum[Item[@Name="Author" and .="Oliveira GC"]]');
$book = $nodes[0];
print_r($book);
Josh Davis
  • 28,400
  • 5
  • 52
  • 67
scoffey
  • 4,638
  • 1
  • 23
  • 27
5

Well, I suspect the solution will be XPATH...

If you're trying to get the title of a book by the id, you'd use the query:

$query = '//DocSum/Id[contains(., "21232919")]';

If you're trying to search for the title of a book:

$query = '//DocSum/Item[@Name="Title" AND contains(., "Metformin")]';

Then just run it:

$xml = simplexml_load_file($url);

$results = $xml->xpath($query);
foreach ($results as $titleElement) {
    $book = simplexml_import_dom(dom_import_simplexml($titleElement)->parentNode);
    // Handle the book here
}

I'm converting back and forth between simplexml and domdocument since that appears to be the only documented way of traversing up the tree...

ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • 1
    Actually, XPath is supported out of the box in SimpleXML, so you don't actually have to convert to DOM or create a DomXpath object. See http://docs.php.net/manual/en/simplexmlelement.xpath.php – Josh Davis Jan 19 '11 at 18:22
  • Thanks @Josh, I've edited it in (but I still need the conversion to access the parent) – ircmaxell Jan 19 '11 at 18:51
  • You can select the parents just with XPath. Check [@scoffey](http://stackoverflow.com/questions/4736417/simplexml-get-element-content-based-on-attribute-value/4736714#4736714)'s answer. –  Jan 22 '11 at 18:32