Php xml loop

Hi all. im trying to loop through an xml, i should be bringing back 3 titles but instead i am brining back 3 of the first title;

Title1
Title1
Title1

i cannot figure out what i am doing wrong, please help. the code im using is below (i have replaced the pathways with path)

$xmlPath = ("xml/test.xml");

$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->validateOnParse = true;
$xmlDoc->load($xmlPath);

$xpath = new DomXPath($xmlDoc);	

$nodepath='//path[@path="'.$testcode.'"]';


$aa = $xpath->query($nodepath.'/path/path/path[@path="true"]');
		if (($aa->length) > 0){
			echo('<ol>');
			foreach ($aa as $titlename){
			  echo('<li><strong>'.$xpath->query($nodepath.'/path/path/path/path',$titlename)->item(0)->nodeValue.'</strong></li>');
			}
			echo('</ol>');
		}else{
			echo('It did not work!');
		} 

->item(0)

Just a guess, but why dont you put a counter in that loop?

->item($ctr++)

test first by doing this:

->item(1)

and see if the title changes to title2.

You should post the full xml example , maybe there is a problem in your xpath also.

I’ll give a short answer, then explain things in a little more detail (though very definitely only a little more detail). It’s up to you which to read. :slight_smile:

Short Answer: You want to use a relative XPath expression, but at the moment you’re using an absolute one.

Longer Answer:

Your code starts the expression with a / which selects the document root (the parent of the document element, which is the single element wrapping everything else). By starting with the slash, you effectively make the expression absolute (think of it as, relative to the document root).

When followed immediately by another / to form // this forms a special syntax which is an abbreviated form of /descendant-or-self::node()/. So, your //path is the same as /descendant-or-self::node()/path, which would match any path element which is a descendant of, or is itself, the document root element.

But that’s not what you want! To turn an absolute path into a relative one, the task is simple; just make sure that the first character is not a /. If a path is not absolute then it is relative, but relative to what? That “what” is called the context node, which is what you provide in the second argument to DOMXPath::query(). (Aside: if you don’t provide a context node to that method, the default context node is the document element.)

So, to ask for path nodes which are descendants of the context node, you can use [noparse]descendant::path[/noparse]. There is no first /, so the path is relative and it asks to look for elements named path on the descendant axis (i.e. a child of the context node, or child of a child of a child of a child of a child… of the context node). As an answer then, you should probably start your XPath expression with descendant::path rather than //path.

Now, that is all that you really need to know but I’m going to go on a little tangent.

Instead of starting paths with descendant:: you will often see the following: .// Mostly because it’s shorter and works pretty much the same as the above, so long as you keep the key difference in mind (more on that in a minute). Both the . and // there are abbreviations (the latter, you already know about!) with the dot meaning self::node(). That matches the context node itself (the only node within the self axis is the context node). When put into use like .//path, hopefully you will now be able to recognise that that looks for self::node()/descendant-or-self::node()/path which in English asks for all path nodes which are descendants of the context node or (importantly) the context node itself if that is a path element. However, for the sake of conciseness .// is often used to match descendants of the context node rather than typing out the clunky descendant::.

Time to stop there, before I get too carried away. (:

Thank you for the responses. I tired using // instead of / but it didnt do anything. yes changing

->item(0) 

to

->item(1)

changes it so it displays 3 of title 2. im at a loss, please can someone help. thank you in advance

Salathe you were right. taking a second look i found that if i took out the $nodepath. it made it a relative path. thanks.