1

Can anyone help explain to me why the following is returning duplicate data?

<?php
$xml_test = '<array key="results">
    <array key="123">
        <string key="mask">1234</string>
    </array>
    <array key="987">
        <string key="mask">5678</string>
    </array>
</array>';

$load_test = simplexml_load_string($xml_test);

foreach ($load_test as $array)
{
    $mask = $array->xpath('//string[@key="mask"]');

    print 'Mask: ' . $mask[0] . '<br />';
}

Returns:

Mask: 1234
Mask: 1234

If I throw a print_r($array) within the foreach loop, I get:

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [key] => 123
        )

    [string] => 1234
)
Mask: 1234

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [key] => 987
        )

    [string] => 5678
)
Mask: 1234

What the hell is going on? Why am I getting duplicate masks when I use an xPath expression when both of the $array quite clearly are not holding duplicate data.

0

3 Answers 3

3

You are making the same xpath query twice, once for each of the <array> nodes in your XML. There is no need for the outer loop. Just do your xpath query, then loop over its results.

$mask = $array->xpath('//string[@key="mask"]');
print 'Mask: ' . $mask[0] . '<br />';
print 'Mask: ' . $mask[1] . '<br />';

Or do the xpath query first, then loop over it:

$mask = $array->xpath('//string[@key="mask"]');
foreach ($mask as $m) {
   echo $m;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, but I'm still confused where the duplicate data is coming from. Does $array within each loop somehow still contain the whole XML structure? and print_r is hiding it or something?
My problem with having the xpath query first is, that I want to perform multiple xpath queries on each array node to match not only mask, but also on keys: id, name and email.
@MichaelP There isn't duplicate data - It's just that because your xpath query starts with ` //, each time you execute it in the loop you get the exact same nodelist returned. So the value $mask[0]` is the same on every loop iteration.
2

Starting the location path in xpath() with / makes it "absolute", whereas you want to query "relative" to the $array element. For your example, just take out the //.

foreach ($load_test as $array)
{
    $mask = $array->xpath('string[@key="mask"]');

    print 'Mask: ' . $mask[0] . '<br />';
}

See also http://www.sitepoint.com/forums/showthread.php?723058-php-xml-loop&p=4778177&viewfull=1#post4778177

Comments

0

Until I can better understand what's going on, the following outputs what I am after; allowing me to match on the key attributes.

$xml_test = '<array key="results">
    <array key="123">
        <string key="mask">1234</string>
        <string key="name">mick</string>
    </array>
    <array key="987">
        <string key="mask">5678</string>
        <string key="name">bob</string>
    </array>
</array>';

$simplexml= new SimpleXMLElement($xml_test);

$test = $simplexml->xpath('//array/array');

$loop = 0;
foreach ($test as $result)
{
    $mask = $result->xpath('//string[@key="mask"]');
    $name = $result->xpath('//string[@key="name"]');

    echo "Mask: " . $mask[$loop] . '<br />';
    echo "Name: " . $name[$loop];
    $loop++;
}

Returns:

Mask: 1234
Name: mick

Mask: 5678
Name: bob

Not sure how clean the above is, but it ultimately does what I need it to do.

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.