rename multiple attributes with simpleXML - php

<root>
<gallery name="First"/>
<gallery name="Second"/>
<gallery name="Third"/>
</root>
I'm trying to rename multiple "name" attributes at once:
$rename = array();
foreach($_POST['name'] as $value) {
$rename[] = $value;
}
$objXML = new SimpleXMLElement(XML_FILE_NAME, null, true);
$gallery = $objXML->xpath('/root/gallery/#name');
print_r($gallery);
print_r($rename);
$objXML->asXML(XML_FILE_NAME);
Returns:
Array ( [0] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => First ) ) [1] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => Second ) ) [2] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => Third ) ) )
Array ( [0] => First New [1] => Second New [2] => Third New )
How can I get php to save the New values back to the XML? Does it need another foreach loop? The code seems to be getting too complex already.
I'm trying this, but no dice:
foreach( $objXML->xpath('/root/gallery/#name') as $gallery ) {
$gallery = $_POST['name'];
}

Simplexml is buid to returns node only. That's weird, but '/root/gallery/#name' and '/root/gallery'.
These two queries
$aList = $objXML->xpath('/root/gallery/#name');
$bList = $objXML->xpath('/root/gallery');
will return the same instances
for($i=0, $count=count($aList); $i<$count; $i++) {
$a = $aList[$i];
$b = $aList[$i];
var_dump($a==$b); // true
}
So the only way for changing the attribute of a node is with the array syntaxe
foreach($aList as $node) {
$node['name'] = 'foo' . $i;
}
var_dump($objXML);

Related

Move elements in multidimensional array

I decoded XML document to an array via a json string like this:
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence',json_encode($xml,true));
$array = json_decode($json,TRUE);
However, the elements with attributes were created with another "#attributes" layer like this:
Array
(
[#attributes] => Array
(
[genre] => electronic
)
[festival] => Array
(
[#attributes] => Array
(
[name] => Berlin
)
[concert] => Array
(
[#attributes] => Array
(
[status] => Not Started
[date] => 24.03.2017
)
[organizers] => Array
(
[person] => Array
(
[#attributes] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
)
How can I remove the "#attributes" layer, so that the resulting array looks like this instead:
Array
(
[genre] => electronic
[festival] => Array
(
[name] => Berlin
[concert] => Array
(
[status] => Not Started
[date] => 24.03.2017
[organizers] => Array
(
[person] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
I tried recursively traversing the array, and I can find the "#attributes", but then I'm having difficulty moving that section one dimension up to get rid of the "#attributes" layer.
Thank you.
Try below solution:
<?php
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence',json_encode($xml,true));
$array = json_decode($json,TRUE);
function removeSpecificKey(&$desired_array, $actualArray, $key_to_remove)
{
if (is_array($actualArray)) {
foreach ($actualArray as $key => $map) {
if ($key !== $key_to_remove) {
$desired_array[$key] = array();
removeSpecificKey($desired_array[$key], $actualArray[$key], $key_to_remove);
} else {
removeSpecificKey($desired_array, $actualArray[$key], $key_to_remove);
}
}
} else {
$desired_array = $actualArray;
}
}
$desired_array = array();
removeSpecificKey($desired_array, $array, '#attributes');
print_r($desired_array);
Output:
Array
(
[genre] => electronic
[festival] => Array
(
[name] => Berlin
[concert] => Array
(
[status] => Not Started
[date] => 24.03.2017
[organizers] => Array
(
[person] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
I'm going to start by saying to you what I say to everyone using more and more convoluted ways of abusing SimpleXML and json_encode - why do you need this? Take a step back, and think about what you're going to use this array for, and why you can't just use SimpleXML itself. Look at the examples in the manual for how you could.
For instance, you want to list the organizers of each festival? Then you'd loop over like this:
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
foreach ( $xml->festival as $festival ) {
echo '<h2>', (string)$festival['name'], '</h2>';
echo '<ul>';
foreach ( $festival->concert as $concert ) {
foreach ( $concert->organizers->person as $organizer ) {
echo '<li>', (string)$organizer['name'], '</li>';
}
}
}
If you still think an array that throws away half the structure of the XML is what you want, then use SimpleXML to create it:
function turn_simplexml_into_broken_array($element) {
// Handle elements with text content
// By the way, this will break if the element has text content
// as well as children or attributes. So will the JSON hack.
// Because XML doesn't fit neatly in an array.
$text_content = trim( (string)$element );
if ( strlen($text_content) > 0 ) {
return $text_content;
}
$array = [];
foreach ( $element->attributes() as $name => $value ) {
$array[$name] = (string)$value;
}
foreach ( $element->children() as $name => $value ) {
// Handle multiple child elements with the same name
// Of course, this means the structure will be different
// for concerts with one organizer that concerts with multiple
// which leaving the object as SimpleXML would have saved you from
if ( count($element->{$name}) > 1 ) {
$array[$name][] = turn_simplexml_into_broken_array($value);
}
else {
$array[$name] = turn_simplexml_into_broken_array($value);
}
}
return $array;
}
$xml = simplexml_load_string($xmldoc);
print_r(turn_simplexml_into_broken_array($xml));
Note that we're not "removing #attributes" here. We're taking the XML attributes, and putting them into an array, along with the child elements.
Obviously, you can hack around with this to better suit the particular XML you're working with, and the structure you want. At which point, ask yourself again why you need a generic function for this at all.

Append new key to an existing array in an object

I have an existing JSON array:
stdClass Object
(
[set] => Array
(
[0] => stdClass Object
(
[name] => agenda
)
[1] => stdClass Object
(
[name] => first aid
)
)
)
I need to add a new key to it, so the final JSON result is something like this:
set: [{
name: 'agenda',
value: 'Agenda'
}, {
code: 'first aid',
value: 'First Aid'
}],
This is what I've done so far:
$result = array();
foreach ($data->set as $k => $row) {
$result['name'][$k] = $row->name;
$result['value'][$k] = ucwords($row->name);
}
But I have ended up with:
Array
(
[name] => Array
(
[0] => agenda
[1] => aid kit
)
[value] => Array
(
[0] => Agenda
[0] => First Aid
)
)
How can I merge the above so the name and value keys are in pair rather then being separate?
Update $row directly to modify your existing $data:
foreach ($data->set as $row) {
$row->value = ucwords($row->name);
}
To do it the way you are attempting:
$result = $data;
foreach ($data->set as $k => $row) {
$result->set[$k]->value = ucwords($row->name);
}
Notice, $row is an object.
Your try this
$result = array();
$count = 0;
foreach ($data->set as $k => $row) {
$result[$count]['name'] = $row->name;
$result[$count]['value'] = ucwords($row->name);
$count++;
}
result this
Array
(
[0] => stdClass Object
(
[name] => agenda
[value] => Agenda
)
[1] => stdClass Object
(
[name] => first aid
[value] => First Aid
)
)
If you want to modify your existing object, you can just set the value property directly.
foreach ($data->set as $row) {
$row->value = ucwords($row->name);
}
If you want to create a result without modifying your original object or leaving references to its internal objects, you can clone each of the internal objects and add the new properties to the cloned objects.
$result = array();
foreach ($data->set as $k => $row) {
$obj = clone $row;
$obj->value = ucwords($row->name);
$result[$k] = $obj;
}

PHP last added in array replaces all stored array values

What I'm trying to do:
Get results from the database.
Get required values by assigning to an stdClass.
Put those objects in array. (<-The problem)
And output as JSON.
The objects are fine they get correct values. But when they are assigned to the array once, they replace all previous array values.
I'm using CodeIgniter to do the DB stuff.
The function:
function get_prizes(){
//All prize objects are stored here
$prizes = array();
//Prize object
$prize = new stdClass();
$prize->name1 = '';
//$prize->type = '';
//Getting the prizes from a simple database table
$query = $this->db->get('prizes');
if($query->num_rows() > 0){
foreach ($query->result() as $row):
$prize_name = $row->prize_name;
$prize->name1 = $prize_name;
//$prize->type = $prize_name;
$prizes[] = $prize;
echo " Item: " . print_r($prizes, true) . "<br>";
endforeach;
}
echo json_encode($prizes);
}
Output:
Item: Array ( [0] => stdClass Object ( [name1] => Radio ) )
Item: Array ( [0] => stdClass Object ( [name1] => Television ) [1] => stdClass Object ( [name1] => Television ) )
Item: Array ( [0] => stdClass Object ( [name1] => Toaster ) [1] => stdClass Object ( [name1] => Toaster ) [2] => stdClass Object ( [name1] => Toaster ) )
[{"name1":"Toaster"},{"name1":"Toaster"},{"name1":"Toaster"}]
I've tried array_push(). Also does the same thing.
You need to instantiate the object inside foreach loop:
function get_prizes()
{
// All prize objects are stored here
$prizes = array();
// Getting the prizes from a simple database table
$query = $this->db->get('prizes');
if ($query->num_rows() > 0) {
foreach($query->result() as $row):
// Prize object
$prize = new stdClass();
// $prize->type = '';
$prize->name1 = $row->prize_name;
$prizes[] = $prize;
endforeach;
}
echo json_encode($prizes);
}

PHP stdClass issue

I try to create an generic object which needs to be structuered like this:
[Content] => stdClass Object
(
[item] => Array
(
[0] => stdClass Object
(
[Value] => STRING
)
)
[item] => Array
(
[0] => stdClass Object
(
[Value] => ANOTHER STRING
)
)
)
This is my code:
$content = new stdClass();
$data = file('filname.csv');
foreach($data as $key => $val) {
$content->item->Value = $val;
}
This overwrites itself each time the loop iterates. By defining item as an array like this:
$content->item = array();
...
$content->item[]->Value = $val;
...the result is also not the estimated.
You are overwritting data each time even using array. You should create temporary object for storing value and then put them to item array.
$content = new \stdClass();
$content->item = array();
foreach($data as $key => $val) {
$itemVal = new \stdClass();
$itemVal->Value = $val;
$content->item[] = $itemVal;
}

Strip an XML object of its object status, and save the value contained inside

I have an object which contains an array, which contains an array, which contains an object:
stdClass Object
(
[path] => Array
(
[0] => Array
(
[0] => SimpleXMLElement Object
(
[0] => 44.6451471575972
)
)
)
)
What I need to turn that into is this:
stdClass Object
(
[path] => Array
(
[0] => Array
(
[0] => 44.6451471575972
)
)
)
Basically I need to get rid of that object, but save the value in that object. Using PHP, how do I do this?
EDIT: Here the code I am using to create the array:
$xml = simplexml_load_file('/Users/jasonburton/Sites/walkabout/csv-importer/xml/'.$old_route_id.'.xml');
$nodes = $xml->xpath('/markers/line/*');
$json = new stdClass;
$json->path = array();
foreach($nodes as $node){
foreach($node->attributes() as $index=>$value){
$values[] = $value;
if(count($values) == 2){
$json->path[] = array($values[0], $values[1]);
unset($values);
$values = array();
}
}
}
print_r($json);
$value is what contains the SimpleXMLObject that needs to be converted into the value.
Thanks!
Type cast $value with string: $values[] = (string)$value;

Categories