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!!
Related
Hi i want to create a php code which generates xml of specific format given below. Kindly help me through this
<?xml version="1.0" encoding="utf-8"?>
<order>
<requisition>
<dateofservice>2012-12-13</dateofservice>
<labid>str1234</labid>
<reqnotes_c>str1234</reqnotes_c>
<rptemail_c>str1234</rptemail_c>
<rptmethod_c>str1234</rptmethod_c>
<specimen_type_c>str1234</specimen_type_c>
<collectiontype_c>str1234</collectiontype_c>
</requisition>
<patient>
<firstname>str1234</firstname>
<lastname>str1234</lastname>
<dob>2012-12-13</dob>
<breed_c>str1234</breed_c>
<species>str1234</species>
<sex>s</sex>
<sterilization_c>str1234</sterilization_c>
</patient>
</order>
My code is this Now correct me please. My code gives only one parent and i want to generate the output as given above
while (($row = fgetcsv($inputFile)) !== FALSE){
$container = $doc->createElement('row');
foreach($headers as $i => $header) {
if(!empty($row[$i])) {
$child = $doc->createElement($header);
$child = $container->appendChild($child);
$value = $doc->createTextNode($row[$i]);
$value = $child->appendChild($value);
}
}
$root->appendChild($container);
}
$strxml = $doc->saveXML();
There is an XML file with a content similar to the following:
<FMPDSORESULT xmlns="http://www.filemaker.com">
<ERRORCODE>0</ERRORCODE>
<DATABASE>My_Database</DATABASE>
<LAYOUT/>
<ROW MODID="1" RECORDID="1">
<Name>John</Name>
<Age>19</Age>
</ROW>
<ROW MODID="2" RECORDID="2">
<Name>Steve</Name>
<Age>25</Age>
</ROW>
<ROW MODID="3" RECORDID="3">
<Name>Adam</Name>
<Age>45</Age>
</ROW>
I tried to sort the ROW tags by the values of Name tags using array_multisort function:
$xml = simplexml_load_file( 'xml1.xml');
$xml2 = sort_xml( $xml );
print_r( $xml2 );
function sort_xml( $xml ) {
$sort_temp = array();
foreach ( $xml as $key => $node ) {
$sort_temp[ $key ] = (string) $node->Name;
}
array_multisort( $sort_temp, SORT_DESC, $xml );
return $xml;
}
But the code doesn't work as expected.
I would recommend using the DOM extension, as it is more flexible:
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$doc->load('xml1.xml');
// Get the root node
$root = $doc->getElementsByTagName('FMPDSORESULT');
if (!$root->length)
die('FMPDSORESULT node not found');
$root = $root[0];
// Pull the ROW tags from the document into an array.
$rows = [];
$nodes = $root->getElementsByTagName('ROW');
while ($row = $nodes->item(0)) {
$rows []= $root->removeChild($row);
}
// Sort the array of ROW tags
usort($rows, function ($a, $b) {
$a_name = $a->getElementsByTagName('Name');
$b_name = $b->getElementsByTagName('Name');
return ($a_name->length && $b_name->length) ?
strcmp(trim($a_name[0]->textContent), trim($b_name[0]->textContent)) : 0;
});
// Append ROW tags back into the document
foreach ($rows as $row) {
$root->appendChild($row);
}
// Output the result
echo $doc->saveXML();
Output
<?xml version="1.0"?>
<FMPDSORESULT xmlns="http://www.filemaker.com">
<ERRORCODE>0</ERRORCODE>
<DATABASE>My_Database</DATABASE>
<LAYOUT/>
<ROW MODID="3" RECORDID="3">
<Name>Adam</Name>
<Age>45</Age>
</ROW>
<ROW MODID="1" RECORDID="1">
<Name>John</Name>
<Age>19</Age>
</ROW>
<ROW MODID="2" RECORDID="2">
<Name>Steve</Name>
<Age>25</Age>
</ROW>
</FMPDSORESULT>
Regarding XPath
You can use DOMXPath for even more flexible traversing. However, in this specific problem the use of DOMXPath will not bring significant improvements, in my opinion. Anyway, I'll give examples for completeness.
Fetching the rows:
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('myns', 'http://www.filemaker.com');
$rows = [];
foreach ($xpath->query('//myns:ROW') as $row) {
$rows []= $row->parentNode->removeChild($row);
}
Appending the rows back into the document:
$root = $xpath->evaluate('/myns:FMPDSORESULT')[0];
foreach ($rows as $row) {
$root->appendChild($row);
}
Some SimpleXMLElement methods return arrays but most return SimpleXMLElement objects which implement Iterator. A var_dump() will only show part of of the data in a simplified representation. However it is an object structure, not a nested array.
If I understand you correctly you want to sort the ROW elements by the Name child. You can fetch them with the xpath() method, but you need to register a prefix for the namespace. It returns an array of SimpleXMLElement objects. The array can be sorted with usort.
$fResult = new SimpleXMLElement($xml);
$fResult->registerXpathNamespace('fm', 'http://www.filemaker.com');
$rows = $fResult->xpath('//fm:ROW');
usort(
$rows,
function(SimpleXMLElement $one, SimpleXMLElement $two) {
return strcasecmp($one->Name, $two->Name);
}
);
var_dump($rows);
In DOM that will not look much different, but DOMXpath::evaluate() return a DOMNodeList. You can convert it into an array using iterator_to_array.
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('fm', 'http://www.filemaker.com');
$rows = iterator_to_array($xpath->evaluate('//fm:ROW'));
usort(
$rows,
function(DOMElement $one, DOMElement $two) use ($xpath) {
return strcasecmp(
$xpath->evaluate('normalize-space(Name)', $one),
$xpath->evaluate('normalize-space(Name)', $two)
);
}
);
var_dump($rows);
DOM has no magic methods to access children and values, Xpath can be used to fetch them. The Xpath function string() converts the first node into a string. It return an empty string if the node list is empty. normalize-space() does a little more. It replaces all groups of whitespaces with a single space and strips it from the start and end of the string.
How can I echo xml values with php by calling their "columnId" and not the position in the array ? (The array is really long)
Here is a sample of the xml :
<Data>
<Value columnId="ITEMS_SOLD">68</Value>
<Value columnId="TOTAL_SALES">682</Value>
<Value columnId="SHIPPING_READY">29</Value>
...
</Data>
The following php gives me all of the values :
$url = 'XXX';
$xml = file_get_contents($url);
$feed = simplexml_load_string($xml) or die("Error: Cannot create object");
foreach($feed->Data->Value as $key => $value){
echo $value;
}
I would like to be able to use something like that in my document :
echo $feed->Data->Value['TOTAL_SALES'];
Thank you for your help.
echo $feed->Data->Value[1];
I have an another way for your solution. You can convert xml object into array and use this for further process. Try this code:
<?php
$url = 'XXX';
//Read xml data, If file exist...
if (file_exists($url)) {
//Load xml file...
$xml = simplexml_load_file($url);
$arrColumn = array();//Variable initialization...
$arrFromObj = (array) $xml;//Convert object to array...
$i = 0;//Variable initialization with value...
//Loop until data...
foreach($xml AS $arrKey => $arrData) {
$columnId = (string) $arrData['columnId'][0];//array object to string...
$arrColumn[$columnId] = $arrFromObj['Value'][$i];//assign data to array...
$i++;//Incremental variable...
}
} else {//Condition if file not exist and display message...
exit('Failed to open file');
}
?>
Above code will store result into array variable $arrColumn and result is:
Array
(
[ITEMS_SOLD] => 68
[TOTAL_SALES] => 682
[SHIPPING_READY] => 29
)
Hope this help you well!
Use XPath. SimpleXML and DOM support it, but SimpleXML has some limits (It can only fetch node lists).
SimpleXML
$feed = simplexml_load_string($xml);
var_dump(
(string)$feed->xpath('//Value[#columnId = "TOTAL_SALES"]')[0]
);
Output:
string(3) "682"
DOM
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
var_dump(
$xpath->evaluate('string(//Value[#columnId = "TOTAL_SALES"])')
);
Output:
string(3) "682"
I have a soap xml that contains a bunch of variables that I need to access. Here is the XML.
`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<searchPersonsResponse xmlns="">
<searchPersonsReturn>
<attributes>
<attributes>
<name>ercreatedate</name>
<values>
<values>201104070130Z</values>
</values>
</attributes>
<attributes>
<name>status</name>
<values>
<values>Stuff1</values>
<values>Stuff2</values>
<values>Stuff3</values>
<values>Stuff4</values>
<values>Stuff5</values>
<values>Stuff6</values>
<values>Stuff7</values>
</values>
</attributes>
</attributes>
<itimDN>blah</itimDN>
<name>Smith, Bob</name>
<profileName>PER</profileName>
<select>false</select>
</searchPersonsReturn>
</searchPersonsResponse>
</soapenv:Body>
</soapenv:Envelope>
I'm trying to access the inner attribute node and pull out the Name and values into a multidimentional array like this ....
$array["status"][0]="stuff1";
$array["status"][1]="stuff2";
$array["status"][2]="stuff3";
$array["status"][3]="stuff4";
so far I have been able to access the nodes but not really get them the way I want. here is the code I have been playing around with .....
$dom_document = new DOMDocument();
$dom_document->loadXML($thexml);
$tag_els_names = $dom_document->getElementsByTagname('name');
$tag_els_values = $dom_document->getElementsByTagname('values');
$data = array();
$data2 = array();
foreach($tag_els_names as $node){
$data[] = array($node->nodeName => $node->nodeValue);
//grabs all the <name> node values
}
$i=0;$j=0;
foreach($tag_els_values as $node){
$j=0;
foreach($node->childNodes as $child) {
$data2[$i][$j] = $child->nodeValue;
//grabs all the value node values
$j++;
}
$i++;
$j=0;
}
Does anyone know an easy way to do this? I think that I have been looking at this for way to long.
How about something like:
$dom_document = new DOMDocument();
$dom_document->loadXML($thexml);
$xpath = new DOMXpath($dom_document);
$attr = $xpath->evaluate("//attribute/attributes");
$names = array();
$values = array();
$i = 0;
foreach($attr as $attr_node) {
$values[i] = array();
foreach($xpath->evaluate("name", $attr_node) as $name){
$names[] = $name->nodeValue;
}
$foreach($xpath->evaluate("value", $attr_node) as $value){
$values[i][] = $value->nodeValue;
}
i++;
}
This would, however, miss the <name> element that's outside of the <attributes> group. Did you mean to be including that?
I figured this out and thought it could help someone else
$doc = new DOMDocument();
$values=array();
if ($doc->loadXML($temp)) {
$attributes = $doc->getElementsByTagName('attributes');
foreach($attributes as $attribute) {
if($attribute->childNodes->length) {
$previous_nodeValue="";
foreach($attribute->childNodes as $i) {
if($i->nodeValue=="status"){
$previous_nodeValue=$i->nodeValue;
}
if($i->nodeName=="values" && $previous_nodeValue== "status"){
foreach($i->childNodes as $j){
$values[]=$j->nodeValue;
}
}
}
$previous_nodeValue="";
}
}
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Best XML Parser for PHP
-----First XML-----str1
<HOME>
<USER_DETAIL>
<LOCATION><![CDATA[MUMBAI]]></LOCATION>
<NAME><![CDATA[RAVI]]></NAME>
<ID><![CDATA[101]]></ID>
</USER_DETAIL>
<USER_DETAIL>
<LOCATION><![CDATA[PUNE]]></LOCATION>
<NAME><![CDATA[MANISH]]></NAME>
<ID><![CDATA[102]]></ID>
</USER_DETAIL>
</HOME>
---Second XML----str2
<USER_DATA>
<DATA>
<DOB><![CDATA[2/11/1959]]></DOB>
<STATUS><![CDATA[single]]></STATUS>
<PROFILE_PIC><![CDATA[101.JPG]]></PROFILE_PIC>
<ID><![CDATA[101]]></ID>
</DATA>
<DATA>
<DOB><![CDATA[6/8/1987]]></DOB>
<STATUS><![CDATA[married]]></STATUS>
<PROFILE_PIC><![CDATA[102.JPG]]></PROFILE_PIC>
<ID><![CDATA[102]]></ID>
</DATA>
</USER_DATA>
I am new to XML.
I have two xml as above I want common xml with all the data of user. In two XML common thing is ID of user. so is there any way to pass xml into function and compare the id in second xml and get the detais of that perticular user and forms a required(Common with all detais) xml.
str1 and str2 is the php variable which contains the above xml respectively.
use below codes to generate a new XML, you can change the nodes based on your requirements. in case you have both XMLs in a file you can use simplexml_load_file($filename); to load the XML and assign it to $str1 and $str2
$str1 = "<HOME>
<USER_DETAIL>
<LOCATION><![CDATA[MUMBAI]]></LOCATION>
<NAME><![CDATA[RAVI]]></NAME>
<ID><![CDATA[101]]></ID>
</USER_DETAIL>
<USER_DETAIL>
<LOCATION><![CDATA[PUNE]]></LOCATION>
<NAME><![CDATA[MANISH]]></NAME>
<ID><![CDATA[102]]></ID>
</USER_DETAIL>
</HOME>";
$str2 = "<USER_DATA>
<DATA>
<DOB><![CDATA[2/11/1959]]></DOB>
<STATUS><![CDATA[single]]></STATUS>
<PROFILE_PIC><![CDATA[101.JPG]]></PROFILE_PIC>
<ID><![CDATA[101]]></ID>
</DATA>
<DATA>
<DOB><![CDATA[6/8/1987]]></DOB>
<STATUS><![CDATA[married]]></STATUS>
<PROFILE_PIC><![CDATA[102.JPG]]></PROFILE_PIC>
<ID><![CDATA[102]]></ID>
</DATA>
</USER_DATA>";
$xml1 = simplexml_load_string($str1);
$xml2 = simplexml_load_string($str1);
//print_r($xml);
$tempArr = array();
foreach( $xml1 as $obj) {
$id = $obj->ID;
$tempArr["$id"]['LOCATION'] = (string)$obj->LOCATION;
$tempArr["$id"]['NAME'] = (string)$obj->NAME;
}
foreach( $xml2 as $obj) {
$id = $obj->ID;
$tempArr["$id"]['DOB'] = (string)$obj->DOB;
$tempArr["$id"]['STATUS'] = (string)$obj->STATUS;
$tempArr["$id"]['PROFILE_PIC'] = (string)$obj->PROFILE_PIC;
}
//print_r($tempArr);
$xml = new DOMDocument('1.0', 'iso-8859-1');
$doc = $xml->createElement('DOCUMENT');
$doc = $xml->appendChild($doc);
foreach( $tempArr as $ky=>$val ) {
$rnod = $xml->createElement('USER_DETAIL');
$rnod = $doc->appendChild($rnod);
//$rnod = $xml->appendChild($rnod);
$dataN0 = $xml->createElement('ID');
$dataN0 = $rnod->appendChild($dataN0);
$nodV = $xml->createTextNode($ky);
$dataN0->appendChild($nodV);
foreach($val as $k=>$v) {
$dataN1 = $xml->createElement($k);
$dataN1 = $rnod->appendChild($dataN1);
$nodV1 = $xml->createTextNode($v);
$dataN1->appendChild($nodV1);
}
}
$newXml = $xml->saveXML();
echo htmlspecialchars($newXml);