PHP - How do I read all attributes of XML items using simpleXML? - php

I'm making a script, that reads through the passed XML file and displays the source code. I've got it almost done, but the item attributes .. I can't find a way to catch them. Here's the code:
$xml = simplexml_load_file("path/to/file.xml");
showTree($xml->children(), 0);
function showTree($value, $i) {
if($value == '') {
foreach($value as $name2 => $value2) {
echo str_repeat('--', $i)." <$name2> \n";
showTree($value2, ($i+1));
echo str_repeat('--', $i)." </$name2> \n";
}
} else { echo str_repeat('--', $i)." ".trim($value)."\n"; }
} // end: function
As I said, it works fine, but doesn't display the attributes, for example:
<item id=2>Item</item>
returns only the:
<item>Item</item>
Thanks for any responses, Mike.

Unless I missread your code something like this should probably be about right.
$xml = simplexml_load_file("path/to/file.xml");
showTree($xml->children(), 0);
function showTree($value, $i) {
if($value == '') {
foreach($value as $name2 => $value2) {
$attribsStr = '';
foreach($value2->attributes() as $attribName => $attribValue) {
$attribsStr .= $attribName . '="' . $attribValue . '"' . ' ';
}
echo str_repeat('--', $i)." <$name2 $attribsStr> \n";
showTree($value2, ($i+1));
echo str_repeat('--', $i)." </$name2> \n";
}
} else { echo str_repeat('--', $i)." ".trim($value)."\n"; }
} // end: function

Have a look at http://php.net/manual/en/simplexmlelement.attributes.php

Related

Getting XML node names without duplicating in simplexml_load_file

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));

PHP Json values with a specified label

I am using json_decode and echoing the values using a nested foreach loop.
Here's a truncated json that I am working on:
[{"product_name":"Product 1","product_quantity":"1","product_price":"2.99"},....
and the loop
foreach($list_array as $p){
foreach($p as $key=>$value) {
$result_html .= $key.": ".$value."<br />";
}
}
This was I am able to echo all key/value pairs.
I have tried using this to echo individual items something like:
foreach($list_array as $p){
foreach($p as $key=>$value) {
echo "Product: ".$p[$key]['product_name'];
echo "Quantity: ".$p[$key]['product_quantity'];
}
}
However I am unable to because it doesn't echo anything.
I would like to be able to show something like:
Product Name: Apple
Quantity: 7
Currently it is showing:
product_name: Apple
product_quantity: 7
How can I remove the key and replace it with a predefined label.
It can be done with:
foreach ($list_array as $p){
$result_html .= 'Product: ' . $p->product_name
. 'Quantity: ' . $p->product_quantity . '<br />';
}
If you are decoding your json into an object you can do it like that.
$list_array = json_decode('[{"product_name":"Product 1","product_quantity":"1","product_price":"2.99"}]');
$result_html = '';
foreach($list_array as $p){
$result_html .= '<div>Product: '.$p->product_name.'</div>';
$result_html .= '<div>Quantity: '.$p->product_quantity.'</div>';
}
echo $result_html;

How to check for circular references in PHP when recursively parsing an associative array?

I created this array with a circular reference:
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
I have a function that recursively prints out the values in an array, but I really couldn't solve the problem of creating a circular reference check. How can you do that?
The current function I have for printing the array is copied below. I haven't included the various attempts I made at doing the circular reference check. They mainly revolved around a strategy of maintaining a $seen array of items that have already been printed for each branch of recursion. This is because I still want to allow the printing of duplicate values, just not printing of a value if it is a parent of the current array being parsed.
The problems I had were figuring out how to add references rather than array copies to this $seen variable. But I'd be happy to use another strategy all together if it worked.
function HTMLStringify($arr)
{
if(is_array($arr)){
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if(is_array($value)){
//Conspicuously missing is a circular reference check,
//causing infinite recursion. After a few failed attempts
//at checking for this (e.g. discovering that array_push doesn't take references)
//I have left it for further study.
//(After all, Javascript's JSON.stringify() doesn't check for circular references)
//TODO: Check for circular references
$html .= HTMLStringify($value, $seen);
}
elseif(is_numeric($value) || is_string($value) || is_null($value))
{
$html .= ' = ' . $value;
}
else
{
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
else
{
return null;
}
}
An adapted version of your code, using the strict in_array check from the answer linked by Ryan Vincent, is shown below:
function HTMLStringify($arr, array $seen = array()) {
if (is_array($arr)) {
$seen[] = $arr;
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if (is_array($value)) {
if (in_array($value, $seen, true)) {
// Deal with recursion in your own way here
$html .= ' [RECURSION]';
} else {
$html .= HTMLStringify($value, $seen);
}
} elseif (is_numeric($value) || is_string($value) || is_null($value)) {
$html .= ' = ' . $value;
} else {
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
return $html . '</ul>';
} else {
return null;
}
}
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
echo HTMLStringify($arr);
Comparing across a number of PHP versions, it looks like this will work for PHP 5.3.15+ and PHP 5.4.5+.
i'm using this function for debugging. Also upgraded to detect recursive link.
function print_table($mixed, $level=9, $_callstack=array()){
if($level<=0){ echo '**LIMIT**'; return; }
if( array_search(serialize($mixed), $_callstack)!==false){
echo '***recursive detected***';
return ;
}
$_callstack[] = serialize($mixed);
if(is_array($mixed)){
echo '<table cellspacing="0" width="100%" border="1">';
foreach($mixed as $key=>$val){
echo '<tr><td width="20%">'.$key.'</td><td>';
if(is_array($val)){
print_table($val,$level-1, $_callstack);
}elseif(is_null($val)){
echo '<span style="color:blue">null</span>';
}elseif($val===false){
echo '<span style="color:red">false</span>';
}elseif($val===true){
echo '<span style="color:green">true</span>';
}elseif(is_numeric($val) && $val>1000000000){
echo $val,' <span style="color:gray">[',date('d-m-Y H:i:s',$val),']</span>';
}elseif($val===''){
echo '<span style="color:blue">empty string</span>';
}else{
echo $val;
}
echo '</td></tr>';
}
echo '</table>';
}else{
var_dump($mixed);
}
}
As you see, i collect serialaized object, then compare it. Serialization required, because simply comparsion recursive object throw a fatal error:
$arr=array(&$arr);
$arr==$arr; // Fatal error: Nesting level too deep - recursive dependency?
// php 5.2.9
But serialization support recursive objects! So, we should compare serialaized strings, but serialization can take a lot of tima and memory.
If you will find another method - let me know :)

Php Multidimensional array for navigation

Needed Navigation Html
Home
Pages
About
Services
Products
Contact
FAQs
Sitemap
Privacy Policy
Column Layouts
1 Column
2 Column (Left Sidebar)
2 Column (Right Sidebar)
3 Column
4 Column
I want to use php arrays and foreach loops to output the needed html.
The php code I have thus far is:
<?php
$data = array("navigation");
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
$data['navigation']['Pages']['About'] = base_url('pages/about');
echo '<ul>';
foreach($data as $nav) {
foreach($nav as $subNavKey => $subNavHref) {
echo "<li><a href='$subNavHref'>$subNavKey</a>";
}
}
echo '</ul>';
?>
I was thinking I would need three foreach loops nested but php warnings/errors are generated when the third loop is reached on lines such as:
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
I'm not quite sure how to test for 3rd level depths such as:
$data['navigation']['Pages']['About'] = base_url('pages/about');
Also, outputting the needed li and ul tags in the proper positions has given me trouble aswell.
Use recursion
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
$data['navigation']['Pages']['About'] = base_url('pages/about');
$data['navigation']['Pages']['About']['Team'] = base_url('pages/team');
$data['navigation']['Pages']['About']['Team']['Nate'] = base_url('pages/nate');
echo "<ul>"
print_list($data);
echo "</ul>"
function print_list($menu) {
foreach($menu as $key=>$item) {
echo "<li>";
if(is_array($item)) {
echo "<ul>";
print_list($item);
echo "</ul>";
} else {
echo "<a href='{$val}'>$key</a>";
}
echo "</li>";
}
}
<?php
function nav($data) {
$html = '<ul>';
foreach ($data as $k => $v) {
if (is_array($v)) {
$html .= "<li>$k" . nav($v) . "</li>";
}
else {
$html .= "<li><a href='$k'>$v</a>";
}
}
$html .= '</ul>';
return $html;
}
echo nav($data);
A recursive function can get the job done:
$items = array(
"Home",
"Pages" => array(
"About",
"Services",
"Products",
"Contact",
"FAQs",
"Sitemap",
"Privacy Policy",
"Column Layouts" => array(
"1 Column",
"2 Column (Left Sidebar)",
"2 Column (Right Sidebar)",
"3 Column",
"4 Column"
)
)
);
function getMenu($array) {
foreach($array as $key => $value) {
if(is_array($value)) {
echo "<li>" . $key . "</li>";
echo "<ul>";
getMenu($value);
echo "</ul>";
} else {
echo "<li>" . $value . "</li>";
}
}
}
echo "<ul>";
getMenu($items);
echo "</ul>";
Output:
You should use a recursive function, for example (Working Demo):
function makeMenu($array)
{
$menu = '';
foreach($array as $key => $value) {
if(is_array($value)) {
$menu .= '<li>' . $key . '<ul>' . makeMenu($value) . '</ul></li>';
}
else {
$menu .= "<li><a href='". $value ."'>" . $value ."</a></li>";
}
}
return $menu;
}
Then call it like:
$data = array(
"Home",
"Pages" => array("About", "Services"),
"Column Layouts" => array("1 Column", "2 Column (Left Sidebar)")
);
echo '<ul>' . makeMenu($data) . '</ul>';

Strange with function to list countries from txt

i have a problem and i can't explain it ,,
first this is my function
function list_countries($id,$name=null,$result=null){
$countries = 'countries.txt';
$selected = '';
echo '<select name="'.$name.'" id="'.$id.'">';
echo '<option disabled>طالب الغد</option>';
if(file_exists($countries)){
if(is_readable($countries)){
$files = file_get_contents($countries);
$files = explode('|',$files);
foreach($files AS $file){
$value = sql_safe($file);
if(strlen($value) < 6){
echo '<option disabled>'.$value.'</option>';
}else{
if($value == $result){
$selected = ' selected="selected" ';
}
echo '<option value="'.$value.'".$selected.'>'.$value.'</option>';
}
}
}else{
echo 'The file is nor readable !';
}
}else{
echo "The file is not exist !";
}
echo '</select>';
}
Now the explain
i have a text file includes a countries names separated with "|"
In this file there is a heading before the countries ,, i mean Like this
U|United Kingdom|United State|UAE etc ..
L|Liberia|Libya etc ..
Now what the function Do is Disabled the Heading , and it's always one character ..
but the strlen function the minimum number that it's give to me is 5 not one .. " This is the first problem
The second one in the $result never equaled the $value and ether i don't know why ??
You need to split twice the file, one for the lines, one for the countries.
Also, since your "country header" is always the first item of each row, you do not need to check using strlen. Just shift out the first item of each row set: that one is the header, the following ones are the countries.
Something like this.
Note that in your code there is a syntax error in the echo that outputs the value, the > symbol is actually outside the quotes.
function list_countries($id,$name=null,$result=null){
$countries = 'countries.txt';
$selected = '';
$text = '<select name="'.$name.'" id="'.$id.'">';
$text .= '<option disabled>ﻁﺎﻠﺑ ﺎﻠﻏﺩ</option>';
if(file_exists($countries)){
if(is_readable($countries)){
$list = file($countries);
foreach($list as $item){
$item = trim($item);
$opts = explode('|', $item);
// The first item is the header.
$text .= "<option disabled>$opts[0]</option>";
array_shift($opts);
foreach($opts as $opt)
{
$value = sql_safe($opt);
$text .= '<option';
if($value == $result)
$text .= ' selected="selected"';
$text .= ' value="'.$value.'"';
$text .= '>'.$value."</option>\n";
}
}
}else{
$text .= "The file is not readable!";
}
}else{
$text .= "The file does not exist!";
}
$text .= '</select>';
return $text;
}
I have slightly modified your code so that the function actually returns the text to be output instead of echoing it; this makes for more reusability. To make the above function behave as yours did, just replace the return with
echo $text;
}
and you're good.

Categories