简体   繁体   中英

php xpath xml parsing for loop only shows first entry

I have a stupid problem with php simplexml xpath which I don't understand.

xml structure:

<tv>
  <programme start="zeitbla" stop="zeitbla2" channel="19">
    <title>erstertitelbla</title>
    <desc>blablabeschreibung</desc>
    <category lang="ja_JP">情報</category>
    <category lang="en">information</category>
  </programme>
  <programme start="zeitbla" stop="zeitbla2" channel="19">
    <title>zweitertitelbla</title>
    <desc>blablabeschreibung</desc>
    <category lang="ja_JP">ニュース・報道</category>
    <category lang="en">news</category>
  </programme>
</tv>

php code:

$domtemp = new domDocument;
$domtemp->load("file.xml");
$fullfile = simplexml_import_dom($domtemp);

foreach($fullfile->programme as $program){
    $category = $program->xpath('//category[@lang="en"]');
    echo $category[0]."\n";
}

My Question is:

Why do i get only the category from the first entry in every loop pass?

Output:

information

information

Edit:

Ive worked around the problem with:

$domtemp = new domDocument;
$domtemp->load("file.xml");
$fullfile = simplexml_import_dom($domtemp);
foreach($sxe->programme as $program){
    $program  = simplexml_load_string($program->asXML());
    $category = $program->xpath('//category[@lang="en"]');
    echo "{$category[0]}\n";

but i still want to know why this doesnt work like i expected.

Greetings

BluBb_mADe

Based on @hakre's comment I've made some adjustments on my answer, so all you have to do is a minor change on the XPath query:

category[@lang="en"]

instead of

//category[@lang="en"]

since this way you'll be able to maintain each programme node as the query context instead of the whole XML document like before. I've created an example in codepad where you can see it fully working:

<?php
$xml = <<<XML
<tv>
  <programme start="zeitbla" stop="zeitbla2" channel="19">
    <title>erstertitelbla</title>
    <desc>blablabeschreibung</desc>
    <category lang="ja_JP">情報</category>
    <category lang="en">information</category>
  </programme>
  <programme start="zeitbla" stop="zeitbla2" channel="19">
    <title>zweitertitelbla</title>
    <desc>blablabeschreibung</desc>
    <category lang="ja_JP">ニュース・報道</category>
    <category lang="en">news</category>
  </programme>
</tv>
XML;

$sxe = new SimpleXMLElement($xml);

foreach($sxe->programme as $program){
    $category = $program->xpath('category[@lang="en"]');
    echo "{$category[0]}\n";
}

Output:

information
news

On a side note , you can use the simplexml_load_file function instead of loading a DOMDocument and then importing it to SimpleXMLElement .

Why do i get only the category from the first entry in every loop pass?

You only get the first entry because you ask for exactly that:

//category[@lang="en"]

This xpath reads: give my any <category> element anywhere in the document. As xpath() returns those in document-order (because the underlying libxml does, compare with: XPath query result order ) and you obtain the first array entry ( $category[0] , the 0 is the first entry), you always get the first entry.

As you can see it is just that you have queried exactly this. The important point here is that you understand the // axis (double-slash). Even thought // is the Descendant Axis (so looking into all children, grandchildren and so forth), using it alone (at the beginning of the query) will first of all go to the root-element (also called document element).

Instead you either just want to look for the direct child (as your XML suggests):

category[@lang="en"]

- OR - the Descendant Axis relative to the context node:

.//category[@lang="en"]
^
`----  this dot prevents to go up to the root element

- OR - the following, more expressive (and longer to write) ones (checkout the different axis that are available):

descendant::category[@lang="en"]
child::category[@lang="en"]

So as you can see, if you understand the query, it's easy to fix.

Hope this gives you the long awaited explanation. BTW this kind of error is somewhat common, you're not the first one asking for this. Just review the xpath query a bit and try to formulate what it does in your own words and compare with the specs. The more fluent you get with Xpath, the more easy it is.

See as well:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM