How can I update children, grouped with id "X", using simpleXML

308 views Asked by At

I am new to simplexml so forgive me if I get some terms mixed up :)

I have the following xml file stored at: js/data.xml:

<users>
  <user>
    <id>2011</id>
    <posX>12</posX>
    <posY>29</posY>
    <title>Senior Developer</title>
  </user>
  <user>
    <id>2022</id>
    <posX>45</posX>
    <posY>87</posY>
    <title>Test22 text</title>
  </user>
</users>

I have a php file with working code to add more users:

$xml = simplexml_load_file("js/data.xml");
    $user = $xml->addChild('user');
    $user->addChild('id',2022);
    $user->addChild('posX',34);
    $user->addChild('posY',67);
    $user->addChild('title','Test33 text');
    // Store new XML code in data.xml
    $xml->asXML("js/data.xml");
    echo $xml->asXML();

This will add a new user into the file. So far so good, no problems here.

If you take a good look at the code, you'll see that this new user I want to add has the same id (2022) as a user in the xml file. This is the same person, so in this case I don't want to add him, but update him. This is where the problems start.

To update him I first need to check if the ID exists. I did some google-ing and searched this site and found a solution given here: php SimpleXML check if a child exists Problem is, I can't get it to work.

This is the modified code of my php file:

$xml = simplexml_load_file("js/data.xml");

//from: https://stackoverflow.com/questions/1560827/php-simplexml-check-if-a-child-exist
if (isset($xml->user->id->2022)) { // c exists
   echo "test";
} else { //else add it
   $user = $xml->addChild('user');
   $user->addChild('id',2022);
   $user->addChild('posX',45);
   $user->addChild('posY',87);
   $user->addChild('title','Test33 text');
}
// Store new XML code in data.xml
$xml->asXML("js/data.xml");
echo $xml->asXML();

So here I try to check if the id exists. If so: echo something, else add the person. Unfortunally, when I run this code I get the following error:

Parse error: syntax error, unexpected T_LNUMBER, expecting T_STRING or T_VARIABLE or '{' or '$' 

Anyone has an idea what I do wrong here?

Second problem I have is updating the children (posX, posY and title) if the id exists (ofcourse ONLY the children grouped with this id) . That part of the code needs to be where the test echo is now. I couldn't find a working solution on this site or google using simplexml. Does anyone has an idea how to do this?

Thank you for your time

2

There are 2 answers

1
michi On BEST ANSWER

Rather use xpath() to select a <user>by <id>:

$xml = simplexml_load_string($x); // assume XML in $x

$id         = "2022";
list($user) = $xml->xpath("/users/user[id = '$id']") + [NULL];

Now check $user. If your XML has the above ID, $user will contain the SimpleXML element.
If not, $user will be NULL.

if (!$user) {
    // create new user
} else  {
    $user->title = "updated!";
}

Please note that the [NULL] at the end of line 3 requires PHP >= 5.4, if you don't have it, use:

list($user) = $xml->xpath("/users/user[id = '$id']") + array(NULL);

see it working: https://eval.in/236618

0
hakre On
Parse error: syntax error, unexpected T_LNUMBER, expecting T_STRING or T_VARIABLE or '{' or '$' 

Anyone has an idea what I do wrong here?

This is quite simple to answer, the main part of the error message is "syntax error, unexpected T_LNUMBER".

Parse error means PHP could not understand the code you've written. That's normally a sign of a typographical mistake (aka syntax error for computers). PHP then tells you with what it had an error with: unexpected T_LNUMBER of which T_LNUMBER is a token name for long number, long as in integer, not specifically long as in way.

// from: https://stackoverflow.com/questions/1560827/php-simplexml-check-if-a-child-exist
if (isset($xml->user->id->2022)) 
                          ^^^^

That is this number there. In PHP to access a field, it needs to start with a letter in the range of A-Z or a-z at that place, not with a letter from a different range like 0-9 as you have it there.

You copied the code too quickly from the existing answer over there most likely because you want to do two things at once:

$idExists = isset($xml->user->id);
$idIs2022 = $idExists && trim($xml->user->id) == 2022;

The first line of code stores the result of whether or not the XML parsed in the SimpleXMLElement $xml has the first user element containing a child-element named id. It still will fail if there is no user element at all.

The second line compares the trimmed text value of that element with the numeric integer value of 2022.

As this is still error prone and a little tedious, using XPath as michi suggests is more elegant here.