Thomas
Thomas

Reputation: 315

PHP, XML & XPath: Display specific nodes

I'm struggling with a task. I'm trying to create a function which shows only Journal elements where Author1 / Auth1 is one of the authors. I do get the three Journal elements listed, but I'm only capable of separating each Journal to a new line. I can't manage to separate each Journal-child in the result (and preferably with text nexto the value) to new lines (<br />).

I have the following XML document:

<Journals>
    <Journal>
        <Title>Title1</Title>
        <AuthorName>Author1</AuthorName> 
        <AuthorName>Author2</AuthorName> 
        <AuthorName>Author3</AuthorName>
        <JournalName>One</JournalName>
    </Journal>
    <Journal>
        <Title>Title2</Title>
        <AuthorName>Author2</AuthorName>
        <AuthorName>Author1</AuthorName>
        <JournalName>Two</JournalName>
    </Journal>
    <Journal>
        <Title>Title3</Title>
        <AuthorName>Author3</AuthorName>
        <JournalName>Three</JournalName>
    </Journal>
    <Journal>
        <Title>Title4</Title>
        <AuthorName>Author3</AuthorName> 
        <AuthorName>Author2</AuthorName> 
        <AuthorName>Author4</AuthorName>
        <JournalName>Four</JournalName>
    </Journal>
    <Journal>
        <Title>Title5</Title>
        <AuthorName>Author2</AuthorName> 
        <AuthorName>Auth1</AuthorName>
        <JournalName>Five</JournalName>
    </Journal>
    <Journal>
        <Title>Title6</Title>
        <AuthorName>Author2</AuthorName> 
        <AuthorName>Author3</AuthorName>
        <JournalName>Six</JournalName>
    </Journal>
</Journals>

And the following PHP document:

<?php
  header('Content-Type: text/html; charset=utf-8');
  error_reporting(E_ERROR | E_WARNING | E_PARSE);


/* FUNCTION FOR ALL ARTICLES PUBLISHED BY Author1 */
  function taskOne()              
    {   
    $doc = new DOMDocument();
    $doc->load("file.xml"); 
    $xml = new DOMXPath($doc);

    $query = $xml->evaluate("/Journals/Journal/AuthorName[contains(. , 'Author1') or contains(. , 'Auth1')]/..");
    foreach ($query as $temp)
      {
      echo $temp->nodeValue . "<br />";
      }
    }
    taskOne();
?>

Now another question: How come using the XPath query: /Journals/Journal[contains(AuthorName, 'Author1') or contains(AuthorName, 'Auth1')]only lists the Journal where Author1 is the top author, and not those where he's child-sibling number two or three? Here's the final output with XPath query: /Journals/Journal/AuthorName[contains(. , 'Author1') or contains(. , 'Auth1')]/..

Title1 Author1 Author2 Author3 One 
Title2 Author2 Author1 Two 
Title5 Author2 Auth1 Five

Here's the final output with XPath query: /Journals/Journal[contains(AuthorName, 'Author1') or contains(AuthorName, 'Auth1')]

Title1 Author1 Author2 Author3 One 

And for clarfications, this is want I'm trying to achieve:

Title: Title1 
Journal author: Author1 
Journal author: Author2 
Journal author: Author3 
Journal name:   One

Title: Title2
Journal author: Author2 
Journal author: Author1 
Journal name:   Two 

Title: Title5 
Journal author: Author2 
Journal author: Auth1 
Journal name:   Five

Upvotes: 3

Views: 93

Answers (1)

Kevin
Kevin

Reputation: 41893

You could just target that <Journal> which has children <AuthorName> that contains that needle that you want. You're already close:

$doc = new DOMDocument();
$doc->loadXML($xml_string);
$xpath = new DOMXpath($doc);

$query = "//Journal[AuthorName[contains(., 'Author1') or contains(., 'Auth1')]]";

$journals = $xpath->query($query);
if($journals->length > 0) {
    foreach($journals as $journal) { // for each of the journal found
        foreach($journal->childNodes as $e) { // loop all its nodes/children
            if(isset($e->tagName)) {
                echo "$e->tagName: " . $e->nodeValue . '<br/>';
            }
        }
        echo '<br/>';
    }
}

Sample Output

Upvotes: 2

Related Questions