how to correctly append xml child elements in php - php

I'm trying to iterate over an array of movie names and am struggling as shown below. I've included the actual output vs expected output. thanks!
$root = new SimpleXMLElement('<movies/>');
$movies = ['foo', 'bar'];
foreach($movies as $movie_name){
$movie_el = buildMovieTag($movie_name);
$root->addChild($movie_el->asXML());
}
function buildMovieTag($name){
$movie_tag = new SimpleXMLElement('<movie/>');
$movie_tag->addChild('name', $name);
return $movie_tag;
}
I'm expecting this:
<?xml version="1.0"?>
<movies>
<movie><name>foo</name></movie>
<movie><name>bar</name></movie>
</movies>
but am getting this:
<?xml version="1.0"?>
<movies><<?xml version="1.0"?> // extra xml tag
<movie><name>foo</name></movie>
/><<?xml version="1.0"?> // extra xml tag
<movie><name>bar</name></movie>
/></movies>

The new SimpleXMLElement then asXML() is the issue.
addChild is enough to make the element then its return value is the node, then subsequent addChild's on the node make the children.
<?php
$root = new SimpleXMLElement('<movies/>');
$movies = ['foo', 'bar'];
foreach($movies as $movie_name) {
$movie = $root->addChild('movie');
buildMovieTag($movie, $movie_name);
}
function buildMovieTag($node, $name) {
$node->addChild('name', $name);
}
echo $root->saveXML();
<?xml version="1.0"?>
<movies><movie><name>foo</name></movie><movie><name>bar</name></movie></movies>
Edit: if your data is more extensive, structure it so its standard key/value array then loop over the items. The actual issue to the original question is noted on the first line of the answer.
<?php
$root = new SimpleXMLElement('<movies/>');
$movies = [
['name'=>'foo', 'released' => '2020-12-01 00:00:00', 'plot' => 'foo is a foofoo'],
['name'=>'bar', 'released' => '2020-12-02 00:00:00', 'plot' => 'bar is a barbar'],
];
foreach ($movies as $movie) {
buildMovieTag($root->addChild('movie'), $movie);
}
function buildMovieTag($node, $data) {
foreach ($data as $key => $item) {
// just year from datetime string
if ($key === 'released') $item = date_create($item)->format('Y');
$node->addChild($key, $item);
}
}
echo $root->saveXML();
Result (manual formatted)
<?xml version="1.0"?>
<movies>
<movie>
<name>foo</name>
<released>2020</released>
<plot>foo is a foofoo</plot>
</movie>
<movie>
<name>bar</name>
<released>2020</released>
<plot>bar is a barbar</plot>
</movie>
</movies>

Related

simplexml_load_string issue accessing attributes

My XML looks like this:
<n10:category xmlns:n10="..." some-id="123">
<n10:name xml:lang="x-default">Name Here</n10:name>
<n10:custom-attributes>
<n10:custom-attribute attribute-id="abc1">1</n10:custom-attribute>
<n10:custom-attribute attribute-id="abc2">false</n10:custom-attribute>
<n10:custom-attribute attribute-id="abc3">false</n10:custom-attribute>
...
To access some-id I call:
$xml = simplexml_load_string(...);
foreach ($xml->attributes() as $key => $value) {
if ($key == 'some-id') {
$data['some_id'] = (string) $value;
}
}
The above works. However, when I try to access attributes of custom-attribute, I get back values (like 1, false, false in the example above, but I am unable to get what the attribute-id is equal to on each record. I've tried:
foreach ... $xml->{'custom-attributes'}->attributes() and it returns null
Also, doing var_dump of $xml in the beginning doesn't seem to include the attribute-id at all.
What am I missing?
Use the xpath method to access the custom-attribute nodes, like this:
<?php
$xml = <<<XML
<?xml version='1.0' standalone='yes'?>
<n10:category xmlns:n10="..." some-id="123">
<n10:name xml:lang="x-default">Name Here</n10:name>
<n10:custom-attributes>
<n10:custom-attribute attribute-id="abc1">1</n10:custom-attribute>
<n10:custom-attribute attribute-id="abc2">false</n10:custom-attribute>
<n10:custom-attribute attribute-id="abc3">false</n10:custom-attribute>
</n10:custom-attributes>
</n10:category>
XML;
$sx = simplexml_load_string($xml);
$sx->registerXPathNamespace('n10', '...');
$customAttributes = $sx->xpath('/n10:category//n10:custom-attribute');
foreach ($customAttributes as $ca) {
echo $ca['attribute-id'] . '<br>';
}
It's important to register the custom namespace to be able to access the nodes belonging to said namespace.

CodeIgniter - Process Simple XML & PHP

in the controller I have _send method. This method returns something like below:
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes' ?>
<status id="555555555" date="Wed, 28 Mar 2013 12:35:00 +0300">
<id>3806712345671174984921381</id>
<id>3806712345671174984921382</id>
<id>3806712345671174984921383</id>
<id>3806712345671174984921384</id>
<state error="Unknown1">Rejected1</state>
<state error="Unknown2">Rejected2</state>
<state error="">Accepted</state>
<state error="">Accepted</state>
</status>
XML;
This method called:
$req = $this->_send('bulk',$all_phones,$this->input->post('message'));
I am unable to create array or object suitable for passing to model for inserting into DB.
Below what I have now.
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml as $child) {
if ($child->getName() == 'id') {
$id[] = $child->id;
}
if ($child->getName() == 'state') {
$state[] = $child;
//$state[] = $child['error'];
}
}
return array_merge($id,$state);
I am attempting to achieve something like this array:
array(0 => array(
'id' => '3806712345671174984921381',
'state' => 'Rejected1',
'state_error' => 'Unknown1'),
1 => array( ....
Problem with error attribute with fault array_merge.
Any ideas?
You can do write this using a simple while statement.
$cnt=$xml->id->count();$i=0;
while($i<$cnt)
{
$new_arr[$i]['id']=(string)$xml->id[$i];
$new_arr[$i]['state'] = (string)$xml->state[$i];
$new_arr[$i]['state_error'] = (string)$xml->state[$i]['error'];
$i++;
}
print_r($new_arr);
Demonstration
This is how you could do it:
// Load XML
$xmlstr = '<?xml version="1.0" standalone="yes" ?>
<status id="555555555" date="Wed, 28 Mar 2013 12:35:00 +0300">
<id>3806712345671174984921381</id>
<id>3806712345671174984921382</id>
<id>3806712345671174984921383</id>
<id>3806712345671174984921384</id>
<state error="Unknown1">Rejected1</state>
<state error="Unknown2">Rejected2</state>
<state error="">Accepted</state>
<state error="">Accepted</state>
</status>';
$xml = new SimpleXMLElement($xmlstr);
// Init
$parsed_data = array();
// Parse Id
foreach ($xml->id as $id)
{
$parsed_data[] = array(
'id' => (string)$id,
'state' => '',
'state_error' => ''
);
}
// Parse State & State Error
$i = 0;
foreach ($xml->state as $state)
{
$parsed_data[$i]['state'] = (string)$state;
$parsed_data[$i]['state_error'] = (string)$state['error'];
$i++;
}
// Output
var_dump($parsed_data);
Here's the output I got:

Find and fill XML nodes from a PHP object

First of all, sorry about my english.
So, I have an XML with a lot of nodes, like:
<first>
<second>
<third/>
<fourth/>
</second>
<fifth>
<sixth>
<seventh/>
</sixth>
</fifth>
</first>
and I have an object, like:
Object{
third: "asd",
fourth: "asdasd",
seventh: "asdasdasd"
}
How can I run through all the nodes of the XML, regardless of their parents, and fill every one of them with the values of the existing properties from the object?
Here's an approach using the SimpleXML:
<?php
$object = (object) array(
'third' => 'asd',
'fourth' => 'asdasd',
'seventh' => 'asdasdasd'
);
$xml = <<<XML
<first>
<second>
<third />
<fourth />
</second>
<fifth>
<sixth>
<seventh />
</sixth>
</fifth>
</first>
XML;
$sxe = new SimpleXMLElement($xml);
foreach ($object as $key => $value) {
$node = $sxe->xpath("//*[./{$key}]");
$node[0]->{$key} = $value;
}
echo $sxe->asXML();
Output:
<?xml version="1.0"?>
<first>
<second>
<third>asd</third>
<fourth>asdasd</fourth>
</second>
<fifth>
<sixth>
<seventh>asdasdasd</seventh>
</sixth>
</fifth>
</first>

inserting an object into an array of objects php

I am trying to write a php script which will insert an object into an array of objects which is originally in XML format. I need to insert the object at a specified index and then be able to re-write the xml file from which the data was pulled with the updated object. Here is the structure of my XML
<?xml version="1.0" encoding="UTF-8"?>
<Bars>
<Bar>
<BarName>Kam's</BarName>
<bar_id>0</bar_id>
<Bartenders>
<Bartender>
<fname>Max</fname>
<lname>Vest</lname>
<imageURL>http://uofi-bars.com/bartenderImages/maxvest.jpg</imageURL>
<shift>2</shift>
</Bartender>
</Bartenders>
<Events>
<Event>
<EventName>Kams event</EventName>
<date>08/10/1989</date>
</Event>
</Events>
<Specials>
<Special>Kam's Special 1</Special>
<Special>Kam's Special 2</Special>
</Specials>
</Bar>
So in other words, if I have a bartender who works at a bar with an id of bar_id = 0, I need to be able to insert that bartender into the array of bartenders for that particular bar.
I use the following php code to create the arrays from XML:
function objectsIntoArray($arrObjData, $arrSkipIndices = array())
{
$arrData = array();
// if input is object, convert into array
if (is_object($arrObjData)) {
$arrObjData = get_object_vars($arrObjData);
}
if (is_array($arrObjData)) {
foreach ($arrObjData as $index => $value) {
if (is_object($value) || is_array($value)) {
$value = objectsIntoArray($value, $arrSkipIndices); // recursive call
}
if (in_array($index, $arrSkipIndices)) {
continue;
}
$arrData[$index] = $value;
}
}
return $arrData;
}
$xmlUrl = "Bars.xml"; // XML
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = objectsIntoArray($xmlObj);
print_r($arrXml);
I guess I just don't know how to refer to this array of objects within an array of objects... Any help would be greatly appreciated!
Thanks!
if you just replace your code:
$xmlUrl = "Bars.xml"; // XML
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = objectsIntoArray($xmlObj);
print_r($arrXml);
with this:
$xmlUrl = "Bars.xml"; // XML
$xmlStr = file_get_contents($xmlUrl);
$xml = new SimpleXMLElement($xmlStr);
$bartenders = $xml->xpath('//Bartenders');
$new_bartender = $bartenders[0]->addChild('Bartender');
$new_bartender->fname = 'test1';
$new_bartender->lname = 'test2';
$new_bartender->imgURL = 'http://test.com';
$new_bartender->shift = '0';
print_r($bartenders);
this should do the trick, just replace the values with appropriate values :) i hope this helps!!

Add child to xml with PHP simpleXml

i have problem with simpleXml and adding new items. This is my xml:
<?xml version="1.0" encoding="utf-8"?>
<root>
<items>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</items>
</root>
Im using this php code:
$xml = simplexml_load_file("myxml.xml");
$sxe = new SimpleXMLElement($xml->asXML());
$newItem = $sxe->addChild("items");
$newItem->addChild("item", $newValue);
$sxe->asXML("myxml.xml");
This is the result:
<?xml version="1.0" encoding="utf-8"?>
<root>
<items>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</items>
<items>
<item>jkl</item>
</items>
</root>
This creates me new items node, but i want add item to the same already existing items node.
then, you should not create new items node:
$xml = simplexml_load_file("myxml.xml");
$sxe = new SimpleXMLElement($xml->asXML());
$itemsNode = $sxe->items[0];
$itemsNode->addChild("item", $newValue);
$sxe->asXML("myxml.xml");
Have you tried doing the following way
$newItem->root->items[0]->addChild("item","Test");
Or
$newItem->root->items->addChild("item","Test");
You can use this class to SimpleXML objects that accept children append
<?php
class MySimpleXMLElement extends SimpleXMLElement
{
/**
* Add SimpleXMLElement code into a SimpleXMLElement
*
* #param MySimpleXMLElement $append
*/
public function appendXML($append)
{
if ($append) {
if (strlen(trim((string)$append)) == 0) {
$xml = $this->addChild($append->getName());
} else {
$xml = $this->addChild($append->getName(), (string)$append);
}
foreach ($append->children() as $child) {
$xml->appendXML($child);
}
foreach ($append->attributes() as $n => $v) {
$xml->addAttribute($n, $v);
}
}
}
}

Categories