1

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

6
  • Could you please list your output? Commented Jul 19, 2013 at 19:44
  • output:informationinformation with linebreak. Commented Jul 19, 2013 at 19:45
  • If you var_dump the $fullfile, do you see everything as normal? Commented Jul 19, 2013 at 19:53
  • all correct, it contains the whole xml file Commented Jul 19, 2013 at 19:55
  • ive tried it but it crashes because of nonvalid dom xml code. Commented Jul 19, 2013 at 20:22

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

ahh nice, this is an simple solution.
@Rolando Isidoro: your answer had a serious flaw (fixed that) and also you didn't provide an explanation. Only to get something working does not mean a lot in programming. If you provide an answer, always try to explain it. That way you will learn as well and the answer is more useful for future users that have different code but probably the same problem.
0

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:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.