So here's an overhaul of your code, with some changes to both your approach and the scheme of your XML, based on your various comments and updates.
So first, instead of creating XML that looks like this:
<root>
<rating>a</rating>
<comment>b</comment>
<item_id>c</item_id>
<status>pending</status>
</root>
You're going to store the XML like this:
<root>
<item id="c">
<rating>a</rating>
<comment>b</comment>
<status>pending</status>
</item>
</root>
This is based on a few of your comments:
You are wanting to add to the XML file rather than overwrite the existing file content. That suggests that you want to store multiple items. This would also explain why you have a property item_id. So rather than having a mess of XML like :
<root>
<rating>a</rating>
<comment>b</comment>
<item_id>c</item_id>
<status>pending</status>
<rating>d</rating>
<comment>e</comment>
<item_id>f</item_id>
<status>pending</status>
<rating>g</rating>
<comment>h</comment>
<item_id>i</item_id>
<status>pending</status>
</root>
where it is impossible to know which item is which, you store each set of item properties on an <item> element. Since you are going to want to easily grab an item based on its item_id in order to update that item, making item_id an attribute of the <item> makes more sense than making it a child of the <item>.
- You want to be able to update the status. This is where having the
item_id stored on the item comes in handy. If someone submits a request with an existing item_id, you can update that item, including its status element. Or you could do it whenever you need to from some other process, etc.
Here's the code I drummed up for this. Note that it currently isn't set up to look for an existing element with that item id, but that should be possible using existing SimpleXML functions/methods.
$item = array();
$item_id = "c";
$item['rating'] = 'a';
$item['comment'] = 'b';
$item['status'] = "pending";
$xml = simplexml_load_file('ratings.xml');
//if ratings.xml not found or not valid xml, create clean XML with <root/>
if($xml === false) {
$xml = new SimpleXMLElement('<root/>');
}
$xml_item = $xml->addChild("item");
$xml_item->addAttribute("id", $item_id);
foreach($item as $name => $value) {
$xml_item->addChild($name, $value);
}
$xml->asXML('ratings.xml');
Notice that one of the major changes I made to your existing code is changing from using array_walk_recursive to a simple foreach. array_walk_recursive for this purpose is a short cut that causes more issues than it solves. For instance, you had to swap your key and value on the $item array, which is confusing. It also isn't necessary for what you currently are doing, since you don't have a multi-dimensional array. And even if you did, array_walk_recursive isn't the right choice to handle looping over the array recursively because it would add each array member to the root of the XML, not add sub-arrays as children of their parent entry as they show up in the actual array. Point being, it's confusing, it doesn't add any value, and using a foreach is a lot more clear on what you are actually doing.
I've also changed
$item['item_id'] = 'c';
to
$item_id = 'c';
and then added it to the item element as an attribute like:
$xml_item->addAttribute("id", $item_id);
This is consistent with the new schema I outlined earlier.
Finally, instead of passing the XML to DOMDocument, I'm just using
$xml->asXML('ratings.xml');
SimpleXML already removes any extra whitespace, so there is no need to use DOMDocument to achieve this.
Based on some of the counterintuitive parts of your original code, it looks like you may have done a decent amount of copy and pasting to get it going. Which is where most of us start, but it's a good idea to be upfront about things like "I don't understand quite what this code is doing, I just grabbed it from a script that did some of what I need." It will save us all a lot of time and grief if we're not assuming you are using the code you have because you need to or it was a conscious decision, etc, and that we have to work within the constraints of that code.
I hope this gets you off to a good start.
Update
I was messing around with it, and came up with the following for updating existing <item> if an item with id set to $item_id already exists. It's a bit clunky, but it tested and it works.
This assumes the $item_id and $item array get set as normal, as well as retrieving the exiting XML, as covered above. I'm providing the lines just before the changes for reference:
$xml = simplexml_load_file('ratings.xml');
//if ratings.xml not found or not valid xml, create clean XML with <root/>
if($xml === false) {
$xml = new SimpleXMLElement('<root/>');
}
//query with xpath for existing item with $item_id
$item_with_id = $xml->xpath("/root/item[@id='{$item_id}']");
// if the xpath returns a result, update that item with new values.
if(count($item_with_id) > 0) {
$xml_item = $item_with_id[0];
foreach($item as $name => $value) {
$xml_item->$name = $value;
}
} else {
// if the xpath returns no results, create new item element.
$xml_item = $xml->addChild("item");
$xml_item->addAttribute("id", $item_id);
foreach($item as $name => $value) {
$xml_item->addChild($name, $value);
}
}
$itemarray?$xml. You print it, but no$xml = ...dom_import_simplexml?$xml->asXML('reviews.xml');?