Getting XML node names without duplicating in simplexml_load_file - php

I'm getting the node names of an XML using this code:
$url = 'https://www.toptanperpa.com/xml.php?c=shopphp&xmlc=e7ef2a0122';
$xml = simplexml_load_file($url) or die("URL Read Error");
echo $xml->getName() . "<br>";
foreach ($xml->children() as $child) {
echo $child->getName() . "<br>";
foreach ($child->children() as $child2) {
echo $child2->getName() . "<br>";
foreach ($child2->children() as $child3) {
echo $child3->getName() . "<br>";
foreach ($child3->children() as $child4) {
echo $child4->getName() . "<br>";
}
}
}
}
I'm getting the nodes and children correctly, however, it's duplicating.
Result is as below:
urunler
urun
urun_aktif
urun_metaKeywords
urun_metaDescription
urun_url
urun
urun_aktif
urun_metaKeywords
urun_metaDescription
urun_url
Should I just use array_unique or is there a better method?
Thanks

i used recursive function this is simple
function getChildrens($x) {
$children = array();
array_push($children, $x->getName());
foreach ($x->children() as $chld) {
$children = array_merge($children, getChildrens($chld));
}
return array_unique($children);
}
echo implode("<br>", getChildrens($xml));

Related

Buffering or moving PHP data to display in a different part of a webpage

I am parsing a very large XML file with XMLReader.
$reader = new XMLReader;
$reader->open('products.xml');
$dom = new DOMDocument;
$xpath = new DOMXpath($dom);
while ($reader->read() && $reader->name !== 'product') {
continue;
}
A while loop is used to display relevant data based on user input as well as building arrays with XML values.
while ($reader->name === 'product') {
$node = $dom->importNode($reader->expand(), TRUE);
if ($xpath->evaluate('number(price)', $node) > $price_submitted) {
$category = $xpath->evaluate('string(#category)', $node);
$name = $xpath->evaluate('string(name)', $node);
$price = $xpath->evaluate('number(price)', $node);
// Relevant search results displayed here:
echo "Category: " . $category . ". ";
echo "Name: " . $name . ". ";
echo "Price: " . $price . ". ";
$nameArray[] = $name;
}
$reader->next('product');
}
The foreach loop below uses the array that is built in the while loop above. I need these values (displayed in this foreach loop below) to appear BEFORE the while loop above displays the relevant search results. With XMLReader, you can only execute one while loop for each time you parse the XML, and I don't want to parse it twice because of memory and overhead issues. What is the best way to do this?
foreach ($nameArray as $names) {
echo $names . " ";
}
Well… there are not many options. The most effectiv straight-forward approach is to store category/name/price in array instead of outputting them directly:
<?php
$data = array();
while ($reader->name === 'product') {
$node = $dom->importNode($reader->expand(), TRUE);
if ($xpath->evaluate('number(price)', $node) > $price_submitted) {
$category = $xpath->evaluate('string(#category)', $node);
$name = $xpath->evaluate('string(name)', $node);
$price = $xpath->evaluate('number(price)', $node);
$data[] = array($category, $name, $price);
$nameArray[] = $name;
}
$reader->next('product');
}
foreach ($nameArray as $names) {
echo $names . " ";
}
foreach ($data as $datum) {
// Relevant search results displayed here:
echo "Category: " . $datum[0] . ". ";
echo "Name: " . $datum[1] . ". ";
echo "Price: " . $datum[2] . ". ";
}
In case that doesn't work memory-wise (you mentioned that XML file is really large) you should use db- or file-backed temporary storage

json and PHP parse

Why i can't get out the values from the json file with PHP?
I get zero values? Have tried for hours.
<?php
$json_string = 'http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=44';
$jsondata = file_get_contents($json_string);
$data = json_decode($jsondata, TRUE);
print_r($data);
echo "<br><br><br><br>";
foreach ($data as $recenttrades) {
echo "VALUES('{$recenttrades->quantity}', '{$recenttrades->price}' ";
}
?>
Update: but can't get the value from primaryname and primarycode.
I have tried this:
$json_string = 'http://pubapi.cryptsy.com/api.php?method=marketdatav2';
$jsondata = file_get_contents($json_string);
$data = json_decode($jsondata, TRUE);
//print_r($data);
foreach ($data["market"] as $markets) {
echo "Primary code: <strong>{$markets['primarycode']}</strong><br>";
foreach($markets as $market) {
foreach($market as $attributes) {
foreach($attributes["recenttrades"] as $recenttrade) {
echo "quantity: " . $recenttrade['quantity'] .", price: " . $recenttrade['price'] . "<br>";
}
}
}
}
Others have mentioned that you're dealing with nested arrays, not objects. Along with pointing out the issue of being nested rather deeply, I would suggest digging down with foreach (I will probably be crucified for this):
<?php
$json_string = 'http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=44';
$jsondata = file_get_contents($json_string);
$data = json_decode($jsondata, TRUE);
//print_r($data);
echo "<br><br><br><br>";
foreach ($data as $markets) {
foreach($markets as $market) {
foreach($market as $attributes) {
foreach($attributes["recenttrades"] as $recenttrade) {
//echo "<pre>";
//print_r($recenttrade);
//echo "</pre>";
echo "VALUES('{quantity: " . $recenttrade['quantity'] ."}', 'price: {" . $recenttrade['price'] . "}')";
}
}
}
}
?>
This will ensure that you grab every recentrades item at this level of the array. This way you are prepared for other markets to be added to the API and your code isn't locked into searching only in the item named "FST".
recenttrades is nested pretty deeply in that array. Try
foreach ($data['return']['markets']['FST']['recenttrades'] as $recenttrades) {
recenttrades is several levels nested, so simply doing foreach($data as $recenttrades) is not sufficient.
You need to do:
$recentTrades = $data['return']['markets']['FST']['recenttrades'];
foreach($recentTrades as $recentTrade) {
...
}
recenttrades is nested deeply and you're asking for arrays, not objects. This seems to work:
foreach ($data['return']['markets']['FST']['recenttrades'] as $recenttrades) {
echo "VALUES('{$recenttrades['quantity']}', '{$recenttrades['price']}' ";
}
In response to your update, where you want to loop over markets, try this:
foreach ($data['return']['markets'] as $market) {
echo "Primary code: <strong>{$market['primarycode']}</strong><br>";
foreach ($market["recenttrades"] as $recenttrade) {
echo "quantity: " . $recenttrade['quantity'] .", price: " . $recenttrade['price'] . "<br>";
}
}

parsing a xml to get some values

http://www.managerleague.com/export_data.pl?data=transfers&output=xml&hide_header=0
These are player sales from a browser game. I want to save some fields from these sales. I am fetching that xml with curl and storing on my server. Then do the following:
$xml_str = file_get_contents('salespage.xml');
$xml = new SimpleXMLElement($xml_str);
$items = $xml->xpath('*/transfer');
print_r($items);
foreach($items as $item) {
echo $item['buyerTeamname'], ': ', $item['sellerTeamname'], "\n";
}
The array is empty and i cant seem to get anything from it. What am i doing wrong?
There is no reason to use cURL or XPath for that. You can do
$url = 'http://www.managerleague.com/export_data.pl?data=transfers&output=xml&hide_header=0';
$transfers = new SimpleXMLElement($url, NULL, TRUE);
foreach($transfers->transfer as $transfer) {
printf(
"%s transfered from %s to %s\n",
$transfer->playerName,
$transfer->sellerTeamname,
$transfer->buyerTeamname
);
}
Live Demo
You forgot a slash in your xpath:
$xml_str = file_get_contents('salespage.xml');
$xml = new SimpleXMLElement($xml_str);
$items = $xml->xpath('/*/transfer');
print_r($items);
foreach($items as $item) {
echo $item->buyerTeamname, ': ', $item->sellerTeamname, "\n";
}
<?php
$xml = simplexml_load_file("test.xml");
echo $xml->getName() . "<br />";
foreach($xml->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
}
?>
Is this what you want?

First and Second last xml nodes

I only want the first and the second last Area nodes - how would I do that here?
$url = "http://developer.multimap.com/API/geocode/1.2/OA10081917657704697?qs=Byker&countryCode=GB";
$results = simplexml_load_file($url);
foreach($results->Location as $location) {
echo "<hr />";
foreach($location->Address as $address) {
foreach($address->Areas as $areas) {
foreach($areas->Area as $area) {
echo $area;
echo "<br />";
}
}
}
}
Update: If you have those foreach-loops anyway you can simply use:
$url = "http://developer.multimap.com/API/geocode/1.2/OA10081917657704697?qs=Byker&countryCode=GB";
$results = simplexml_load_file($url);
foreach($results->Location as $location) {
foreach($location->Address as $address) {
foreach( $address->Areas as $areas) {
// <-- todo: add test if those two elements exist -->
echo $areas->Area[0], ' - ', $areas->Area[count($areas->Area)-1], "\n";
}
}
}
You can use XPath for this.
<?php
$doc = new SimpleXMLElement('<foo>
<bar>a</bar>
<bar>b</bar>
<bar>c</bar>
<bar>x</bar>
<bar>y</bar>
<bar>z</bar>
</foo>');
$nodes = $doc->xpath('bar[position()=1 or position()=last()-1]');
foreach( $nodes as $n ) {
echo $n, "\n";
}
prints
a
y
see also:
PHP Manual: SimpleXMLElement::xpath()
XPath: predicates
XPath: position()
XPath: last()
Here it is:
<?php
$url = 'http://developer.multimap.com/API/geocode/1.2/OA10081917657704697?qs=Byker&countryCode=GB';
$results = simplexml_load_file($url);
$areas = array();
foreach ($results->Location->Address->Areas->Area as $area)
{
$areas[] = (string) $area;
}
$first = $areas[0];
$second_last = $areas[count($areas)-2];
?>

Inject XML into a node using a string

I am rebuilding a nodes children by saving them out to an array as strings, trashing them in the XML, inserting a new child node into the array as a string... now I want to loop through the array and write them back out to the original node. The problem is I can't find anything on how to add a child node using a string.
See below for my code. Thanks!!!
$xml = simplexml_load_file($url);
$questionGroup = $xml->qa[intval($id)];
$children = array(); // create empty array
foreach ($questionGroup->children() as $element) { // loop thru children
array_push($children, $element->asXML()); // save XML into array
}
//unset($questionGroup->answer);
//unset($questionGroup->question);
//create new node
$newNode = '<answer><title>'.$title.'</title><description>'.$description.'</description><subName>'.$subName.'</subName><date>'.$date.'</date><timestamp>'.$timestamp.'</timestamp></answer>';
echo "children count: ".count($children);
echo "<br /><br />";
print_r($children);
echo "<br /><br />";
// insert new
array_splice($children,intval($elementIndex),0,$newNode);
echo "children count: ".count($children);
echo "<br /><br />";
print_r($children);
echo "<br /><br />";
echo $questionGroup->asXML();
foreach ($children as $element) { // loop thru array
echo "<br /><br />";
echo $element;
//$questionGroup->addChild(simplexml_load_string($element)); // add array element to the empty questionGroup
}
echo "<br /><br />";
echo "questionGroup: ".$questionGroup;
UPDATE:
I found a function that I modified and was able to get working:
function append_simplexml(&$simplexml_to, &$simplexml_from)
{
$childNode = $simplexml_to->addChild($simplexml_from->getName(), "");
foreach ($simplexml_from->children() as $simplexml_child)
{
$simplexml_temp = $childNode->addChild($simplexml_child->getName(), (string) $simplexml_child);
foreach ($simplexml_child->attributes() as $attr_key => $attr_value)
{
$simplexml_temp->addAttribute($attr_key, $attr_value);
}
// append_simplexml($simplexml_temp, $simplexml_child);
}
}
With this usage in my foreach() loop:
foreach ($children as $element) { // loop thru array
append_simplexml($questionGroup, new SimpleXMLElement($element));
}
You can't do that with SimpleXML alone. There is a nice way to do this with the DOM extension and the DOMDocumentFragment class. (Please note that I didn't try to understand your logic in the example provided, but you should be able to implement the simple sample below into your code).
$xml = simplexml_load_string('<root><parent/></root>');
// get the parent node under which you want to insert your XML fragement
$parent = dom_import_simplexml($xml->parent);
// create the XML fragment
$fragment = $parent->ownerDocument->createDocumentFragment();
// append the XML literal to your fragment
$fragment->appendXML('<child id="1"/><child id="2"><grandchild/></child>');
// append the fragment to the parent node
$parent->appendChild($fragment);
echo $xml->asXML();
/*
* <?xml version="1.0"?>
* <root><parent><child id="1"/><child id="2"><grandchild/></child></parent></root>
*/
Links:
dom_import_simplexml()
DOMDocument::createDocumentFragment()
DOMDocumentFragment::appendXML()
DOMNode::appendChild()
SimpleXMLElement::asXML()
I found a function that I modified and was able to get working:
function append_simplexml(&$simplexml_to, &$simplexml_from)
{
$childNode = $simplexml_to->addChild($simplexml_from->getName(), "");
foreach ($simplexml_from->children() as $simplexml_child)
{
$simplexml_temp = $childNode->addChild($simplexml_child->getName(), (string) $simplexml_child);
foreach ($simplexml_child->attributes() as $attr_key => $attr_value)
{
$simplexml_temp->addAttribute($attr_key, $attr_value);
}
// append_simplexml($simplexml_temp, $simplexml_child);
}
}
With this usage in my foreach() loop:
foreach ($children as $element) { // loop thru array
append_simplexml($questionGroup, new SimpleXMLElement($element));
}
You should be able to do something like this:
$child = new SimpleXMLElement($newNode);
$yourxmlobject->addChild($child);

Categories