How to acces this assoc array?
Array
(
[order-id] => Array
(
[0] => 1
[1] => 2
)
)
as a result of XML parsing
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE request SYSTEM "http://shits.com/wtf.dtd">
<request version="0.5">
<order-states-request>
<order-ids>
<order-id>1</order-id>
<order-id>2</order-id>
...
</order-ids>
</order-states-request>
</request>
$body = file_get_contents('php://input');
$xml = simplexml_load_string($body);
$src = $xml->{'order-states-request'}->{'order-ids'};
foreach ($src as $order) {
echo ' ID:'.$order->{'order-id'};
// dont work - echoes only ID:1, why?
}
// ok, lets try just another way...
$items = toArray($src); //googled function - see at the bottom
print_r($items);
// print result - see at the top assoc array
// and how to acces order ids in this (fck) assoc array???
//------------------------------------------
function toArray(SimpleXMLElement $xml) {
$array = (array)$xml;
foreach ( array_slice($array, 0) as $key => $value ) {
if ( $value instanceof SimpleXMLElement ) {
$array[$key] = empty($value) ? NULL : toArray($value);
}
}
return $array;
}
MANY THANKS FOR ANY HELP!
What you want is:
$body = file_get_contents('php://input');
$xml = simplexml_load_string($body);
$src = $xml->{'order-states-request'}->{'order-ids'}->{'order-id'};
foreach ($src as $id)
{
echo ' ID:', $id, "\n";
}
Live DEMO.
What happens with your code is that you're trying to loop:
$xml->{'order-states-request'}->{'order-ids'}
Which is not the array you want, order-id is, as you can see on your dump:
Array
(
[order-id] => Array
Related
Have a question about mtownsend/request-xml (XML to array) plugin.
So, plugin makes XML file to array.
I use it in my Laravel projects and there is several reason, because I need exact it, but here is one problem.
Have two simple XML files
first file oneitem.xml with one item <flat> into <post>
<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
</post>
</data>
second file severalitems.xml one with several items <flat> into <post>:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
<flat>
<roms>5</roms>
<baths>1</baths>
</flat>
<flat>
<roms>7</roms>
<baths>3</baths>
</flat>
</post>
</data>
Then, I use a simple code to make an array from this files, and show the result array for each:
$xmlone = XmlToArray::convert(file_get_contents('public/xml/test/oneitem.xml'));
$oneflat = $xmlone['post'];
print_r($oneflat);
$xmlseveral = XmlToArray::convert(file_get_contents('public/xml/test/severalitems.xml'));
$severalflats = $xmlseveral['post'];
print_r($severalflats);
If we try to make an array from first file (with one flat), and find all we have in posts we have this result:
Array ( [flat] => Array ( [roms] => 4 [baths] => 2 ) )
If we do the same in second file (with several `flat), we have this result
Array ( [flat] => Array ( [0] => Array ( [roms] => 4 [baths] => 2 ) [1] => Array ( [roms] => 5 [baths] => 1 ) [2] => Array ( [roms] => 7 [baths] => 3 ) )
So, if we have several items, plugin adds a additional arrays with keys, [0], [1], [2]....
I need to do it the same, even there is just one item flat into posts. So the results have same formats.
I know, that it makes plugin. If plugin see, that there is just one flat in post, he makes result array simple.
The code of main file of plugin is here, but I cant understand, which lines do it...
Thanks for your help
public static function convert($xml, $outputRoot = false)
{
$array = self::xmlStringToArray($xml);
if (!$outputRoot && array_key_exists('#root', $array)) {
unset($array['#root']);
}
return $array;
}
protected static function xmlStringToArray($xmlstr)
{
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = self::domNodeToArray($root);
$output['#root'] = $root->tagName;
return $output;
}
protected static function domNodeToArray($node)
{
$output = [];
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = self::domNodeToArray($child);
if (isset($child->tagName)) {
$t = $child->tagName;
if (!isset($output[$t])) {
$output[$t] = [];
}
$output[$t][] = $v;
} elseif ($v || $v === '0') {
$output = (string) $v;
}
}
if ($node->attributes->length && !is_array($output)) { // Has attributes but isn't an array
$output = ['#content' => $output]; // Change output into an array.
}
if (is_array($output)) {
if ($node->attributes->length) {
$a = [];
foreach ($node->attributes as $attrName => $attrNode) {
$a[$attrName] = (string) $attrNode->value;
}
$output['#attributes'] = $a;
}
foreach ($output as $t => $v) {
if (is_array($v) && count($v) == 1 && $t != '#attributes') {
$output[$t] = $v[0];
}
}
}
break;
}
return $output;
}
}
** Thanks for your help!**
Looks like its not posstible. As I understood, standart PHP tools to XML to array convertation makes it so. The plugin based on them.
Anyway, I think there is a way to solve it throught changing source code of this plugin, but I soleved in my situation, by workung with results of XML to array convertation, and check if result array have one flat or several.
I have the following object:
object(SimpleXMLElement)#337 (1) { [0]=> string(4) "1001" }
But I can't seem to access it using [0] or even not using foreach($value as $obj=>$objvalue)
What am I doing wrong?
SimpleXMLElement implements Traversable, which means you could use foreach to loop it.
Try to use
$objectarray = get_object_vars(object(SimpleXMLElement));
By looking into the SimpleXMLElement manual I found this example (the example XML file is on the top of the page of the link):
$movies = new SimpleXMLElement($xmlstr);
/* For each <character> node, we echo a separate <name>. */
foreach ($movies->movie->characters->character as $character) {
echo $character->name, ' played by ', $character->actor, PHP_EOL;
}
And I found this function to transform the XML object to an array, maybe that's easier to use?:
function toArray($xml) { //$xml is of type SimpleXMLElement
$array = json_decode(json_encode($xml), TRUE);
foreach ( array_slice($array, 0) as $key => $value ) {
if ( empty($value) ) $array[$key] = NULL;
elseif ( is_array($value) ) $array[$key] = toArray($value);
}
return $array;
}
I have this link http://lazhalazha.livejournal.com/data/rss with RSS in it, what I need to get is array of guid values, that is links to the post. This is what I have so far...
$xml = simplexml_load_file('http://lazhalazha.livejournal.com/data/rss');
foreach ($xml->channel->item as $item){
print_r($item->guid);
}
Output is series of these objects
SimpleXMLElement Object
(
[#attributes] => Array
(
[isPermaLink] => true
)
[0] => http://lazhalazha.livejournal.com/713.html
)
Solved this by converting this object to string, then it's passing correct URL instead of object.
$xml = simplexml_load_file('http://lazhalazha.livejournal.com/data/rss');
$linkArray = array();
foreach ($xml->channel->item as $item){
$guid = (string)$item->guid;
array_push($linkArray, $guid);
}
<?php
$_temp = array();
$xml = simplexml_load_file('http://lazhalazha.livejournal.com/data/rss');
foreach ($xml->channel->item as $item){
$_temp[] = (string)$item->guid[0];
}
print_r($_temp);
?>
I have some Json being returned from facebook which I'm then parsing in to an array using json _decode. The data ends up looking like this (this is just the snippet I'm interested in):
( [data] =>
Array ( [0] =>
Array (
[id] => 1336269985867_10150465918473072
[from] =>
Array ( [name] => a name here
[category] => Community
[id] => 1336268295867 )
[message] => A message here
Now I've been able to iterate over this data and get what I need:
$jsonDecoded = json_decode($json, true);
$xmlOutput = '<?xml version="1.0"?><data><items>';
foreach ($jsonDecoded as $e) {
foreach ($e as $i) {
$xmlOutput .= '<item><timestamp>' . $i['created_time'] . '</timestamp><title><![CDATA[ ' . $i['message'] .' ]]></title><link>' . $link . '</link><type>facebook</type></item>';
}
}
$xmlOutput .= '</items></data>';
..up until now where I need to check on the from->id value.
I added this line in the second for each:
foreach ($e as $i) {
if($i['from']['id'] == '1336268295867') {
But this just gives me an error:
Fatal error: Cannot use string offset as an array in /Users/Desktop/Webs/php/getFeeds
Any ideas why? I'm sure this is the correct way to get at that value and in actual fact if I echo this out in my loop instead of doing the if statement above I get the value back:
$jsonDecoded = json_decode($json, true);
$xmlOutput = '<?xml version="1.0"?><data><items>';
foreach ($jsonDecoded as $e) {
foreach ($e as $i) {
echo $i['from']['id']
This returns me all of the from->id values in the code returned from facebook and then following this I get the error:
133626829985867133626829985867133626829985867133626829985867195501239202133626829985867133626829985867133626829985867133626829985867133626829985867
Fatal error: Cannot use string offset as an array in /Users/Desktop/Webs/php/getFeeds.php on line 97
(line 97 is the echo line)
Your code makes a lot of assumptions about $i['from']['id'] and at least one of them is incorrect for at least one entry.
Let's add some tests:
$jsonDecoded = json_decode($json, true);
$xmlOutput = '<?xml version="1.0"?><data><items>';
foreach ($jsonDecoded as $e) {
if ( !is_array($e) ) {
die('type($e)=='.gettype($e).'!=array');
}
foreach ($e as $i) {
if ( !is_array($i) ) {
die('type($i)=='.gettype($i).'!=array');
}
else if ( !array_key_exists('from', $i) ) {
die('$i has no key "from"');
}
else if ( !is_array($i['from']) ) {
die('type($i["from"])=='.gettype($i['from']).'!=array');
}
else if ( !array_key_exists('id', $i['from']) ) {
var_dump($i);
die('$i["from"] has no key "id"');
}
echo $i['from']['id'];
}
}
And then you can add a var_dump(...) before the die(...) to take a look at the actual data.
It seems to me that (according to the last code snippet) at some point your $i is not an array anymore. Try to do:
$jsonDecoded = json_decode($json, true);
$xmlOutput = '<?xml version="1.0"?><data><items>';
foreach ($jsonDecoded as $e) {
foreach ($e as $i) {
if(is_array($i))
echo $i['from']['id']
Been trying to figure this out for a short while now but having now luck, for example I have an external xml document like this:
<?xml version="1.0" ?>
<template>
<name>My Template Name</name>
<author>John Doe</author>
<positions>
<position>top-a</position>
<position>top-b</position>
<position>sidebar-a</position>
<position>footer-a</position>
</positions>
</template>
How can I process this document to create variables like this:
$top-a = top-a;
$top-b = top-b;
$sidebar-a = sidebar-a;
$footer-a = footer-a
If you can't make them into variables, how would you put them into an array?
Any help will be greatly appreciated.
From the PHP web site at http://www.php.net/manual/en/function.xml-parse.php:
Ashok dot 893 at gmail dot com 26-Apr-2010 05:52
This is very simple way to convert all applicable objects into associative array. This works with not only SimpleXML but any kind of object. The input can be either array or object. This function also takes an options parameter as array of indices to be excluded in the return array. And keep in mind, this returns only the array of non-static and accessible variables of the object since using the function get_object_vars().
<?php
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;
}
?>
Usage:
<?php
$xmlUrl = "feed.xml"; // XML feed file/URL
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = objectsIntoArray($xmlObj);
print_r($arrXml);
?>
This will give the following result:
Array
(
[name] => My Template Name
[author] => John Doe
[positions] => Array
(
[position] => Array
(
[0] => top-a
[1] => top-b
[2] => sidebar-a
[3] => footer-a
)
)
)
You want the built in class Simplexml
Take a look at SimpleXML:
http://www.php.net/manual/en/simplexml.examples-basic.php
It parses XML into a "map-like" structure which you could then use to access your content. For your particular case,
$xml = new SimpleXMLElement($xmlstr);
$top_a = $xml->template->positions[0]
The simplest method is to use SimpleXML:
$xml = simplexml_load_string(... your xml here...);
$values = array()
foreach($xml->positions as $pos) {
$values[$pos] = $pos;
}
You do not want to auto-create variables in the manner you suggest - it litters your variable name space with garbage. Consider what happens if someone sends over an XML snippet which has <position>_SERVER</position> and you create a variable of that name - there goes your $_SERVER superglobal.
why not doing the array directly?
var positions = document.getElementsByTagName("positions");
var positions_final_arr = [];
for(int i = 0; i < positions.length; i++){
positions_final_arr[i] = [];
var inner_pos = positions[i].getElementsbyTagName("position");
for(int l = 0; l < inner_pos.length; l++){
positions_final_arr[i][l] = inner_pos[i].value;
}
}
console.log(positions_final_arr);
$str = "your xml";
$xml = simplexml_load_string($str);
$result = array();
foreach ($xml->positions as $pos) {
foreach ($pos->position as $p) {
$element = (string)$p[0];
$result[$element] = $element;
}
}
var_dump($result);
Use SimpleXML to parse the file into an object/array structure, then simply use list:
$sxml = new SimpleXMLElement($xml);
$positions = (array)$sxml->positions->children();
list($top_a, $top_b, $sidebar_a, $footer_a) = $positions['position'];
$dom = new DOMDocument;
$dom->loadXML('<root><position>a</position></root>'); //your string here
//$dom->loadXML(file_get_contents($file_with_pxml)); - from file
$position = $dom->getElementsByTagName('position');
for ($i=0; $i<$position->length; $i++)
{
$item = $position->item($i);
${$item->nodeValue} = $item->nodeValue;//$$item->nodeValue = $item->nodeValue;
}
But as I know - you can't create variable with dash in name in PHP
<?php
$xmlUrl = "feed.xml"; // XML feed file/URL
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = json_decode(json_encode($xmlObj), true); # the magic!!!
print_r($arrXml);
?>
This will give the following result:
Array
(
[name] => My Template Name
[author] => John Doe
[positions] => Array
(
[position] => Array
(
[0] => top-a
[1] => top-b
[2] => sidebar-a
[3] => footer-a
)
)
)