B765
B765

Reputation: 35

PHP SimpleXML xpath query results

I have searched for this and the answers I find seem to say what I thought I understand. Obviously I am missing something. I am confused at the results from the xPath query. I have simplified my problem for a test case to post here.

My real xml has several dataset nodes at different depths. Ultimately, I want to get every dataset element with a given label and then loop over that and get the field values (at different locations (or depths) so I think I need xpath). I can use xpath to get the dataset elements that I want successfully. However, when I then run xpath on that result object, it gets me the fields I want and all the other fields too. I can't figure out why it isn't only returning field1, field2, and field3. When I print_r($value[0]), it shows only the fields I want. But, when I run xpath on $value[0], it returns all fields in the xml doc.

Sample XML

<myxml>
    <dataset label="wanteddata" label2="anotherlabel">
        <dataitem>
            <textdata>
                <field label="label1">field1</field>
                <field label="label2">field2</field>
                <field label="label3">field3</field>
            </textdata>
        </dataitem>
    </dataset>
    <dataset label="unwanteddata" label2="unwantedanotherlabel">
        <dataitem>
            <textdata>
                <field label="label4">field4</field>
                <field label="label5">field5</field>
                <field label="label6">field6</field>
            </textdata>
        </dataitem>
    </dataset>
</myxml>

Here is the test code.

$xmlstring = file_get_contents('simplexml_test.xml');
$xml = simplexml_load_string($xmlstring);
if ($xml === false) { 
    throw new Exception("Failed to load");
}

$value = $xml->xpath('//dataset[@label="wanteddata"]');
print_r($value[0]->xpath('//field'));

Code Output:

Array
(
[0] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label1
            )
    )
[1] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label2
            )
    )
[2] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label3
            )
    )
[3] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label4
            )
    )
[4] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label5
            )
    )
[5] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [label] => label6
            )
    )
)

Upvotes: 2

Views: 1751

Answers (1)

har07
har07

Reputation: 89285

//field selects all <field> elements within the entire XML document regardless of the context node from which you call that XPath. To make the XPath heed the context node, you need to add a dot (.) at the beginning of the XPath. In XPath, (.) references current context node :

print_r($value[0]->xpath('.//field'));

Upvotes: 2

Related Questions