Search Value In Object PHP - php

I want to search title in this object and if find the title get link:
array(1) {
["item"]=>
array(13892) {
[0]=> object(SimpleXMLElement)#2 (6) {
["part"]=> string(1) "0"
["search"]=> string(15) "Superfrog Disk1"
["rom_console"]=> string(1) "6"
["title"]=> string(107) "<span class="iconochive-Uplevel" title="Parent Directory" aria-hidden="true"></span> Go to parent directory"
["link"]=> string(75) "https://archive.org/download/3ds-main-encrypted//details/3ds-main-encrypted"
["id"]=> object(SimpleXMLElement)#13894 (0) {}
}
[1]=> object(SimpleXMLElement)#3 (6) {
["part"]=> string(1) "0"
["search"]=> string(15) "Superfrog Disk1"
["rom_console"]=> string(1) "6"
["title"]=> string(53) "100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z"
["link"]=> string(121) "https://archive.org/download/3ds-main-encrypted/100%25%20Pascal%20Sensei%20-%20Kanpeki%20Paint%20Bombers%20%28Japan%29.7z"
["id"]=> object(SimpleXMLElement)#13894 (0) {}
}
}
}
Here is what I try:
$myXMLData = file_get_contents('file.txt');
$xml=simplexml_load_string($myXMLData) or die("Error: Cannot create object");
function _xml2array ( $xmlObject, $out = array () ){
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? _xml2array ( $node ) : $node;
return $out;
}
function find_role($object, $id) {
foreach ($object->item as $inside_object) {
if ($id == $inside_object->title) {
return $inside_object->link;
}
}
return false;
}
$objectxx = _xml2array($xml);
echo find_role($objectxx, "100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z");
In the file.txt I have somthing like this:
<?xml version="1.0"?>
<ArrayOfItem xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item>
<part>0</part>
<search>Superfrog Disk1</search>
<rom_console>6</rom_console>
<title><span class="iconochive-Uplevel" title="Parent Directory" aria-hidden="true"></span> Go to parent directory</title>
<link>https://archive.org/download/3ds-main-encrypted//details/3ds-main-encrypted</link>
<id />
</item>
<item>
<part>0</part>
<search>Superfrog Disk1</search>
<rom_console>6</rom_console>
<title>100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z</title>
<link>https://archive.org/download/3ds-main-encrypted/100%25%20Pascal%20Sensei%20-%20Kanpeki%20Paint%20Bombers%20%28Japan%29.7z</link>
<id />
</item>
<item>
<part>0</part>
<search>Superfrog Disk1</search>
<rom_console>6</rom_console>
<title>View Contents</title>
<link>https://archive.org/download/3ds-main-encrypted/100%25%20Pascal%20Sensei%20-%20Kanpeki%20Paint%20Bombers%20%28Japan%29.7z/</link>
<id />
</item>
</ArrayOfItem>

If you tried to use the SimpleXML library properly, you would simplify your code a lot.
Firstly, you can load the file directly rather than having to read the file and then decode the element. Mainly that you can use object notation to access elements inside another element (i.e. $item->title), so you don't need to convert the data to arrays all the time.
Something like
$xml = simplexml_load_file('a.xml');
function find_role($xml, $id)
{
foreach ($xml->item as $item) {
if ($id == $item->title) {
return (string)$item->link;
}
}
return false;
}
echo find_role($xml, '100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z');
The only real complication is that each item is a SimpleXMLElement, so sometimes you need to cast it to a string to make sure you get the value and not the object (as in return (string)$item->link;).
As a sub note - you can also use XPath to find the elements for you, but that may be beyond the scope of what you are trying to do.

You can also use XPath:
$myXMLData = file_get_contents('file.txt');
$xml=simplexml_load_string($myXMLData) or die("Error: Cannot create object");
$title = '100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z';
$item = current($xml->xpath("//item[title='$title']"));
echo (string) $item?->link;
Or create your own class:
$myXMLData = file_get_contents('file.txt');
$library = simplexml_load_string($myXMLData, Library::class) or die("Error: Cannot create object");
echo $library->findRole('100% Pascal Sensei - Kanpeki Paint Bombers (Japan).7z');
class Library extends SimpleXMLElement
{
public function findRole(string $title): ?string
{
$item = current($this->xpath("//item[title='$title']"));
return $item ? (string) $item->link : null;
}
}

Related

SimpleXML_Load_String on XML with nested image tags not capturing the "url" attribute

I am attempting to parse xml using simplexml_load_string on an old server running PHP 5.3. One of the tags in the xml is and has several nested children with a url attribute. If I var_dump the SimpleXMLElement, images is just an array of strings (the text node children of each tag) with no sign of the url attribute.
Any thoughts on why the url attribute on the tags is not being captured?
I've tried shortening the url attributes on the image tags to about 15 characters and they're still not captured.
I've tried accessing the attributes as an array element of the image element as well as by calling the attributes() method on the image element.
Sample XML
<properties xmlns:xs="http://www.w3.org/2001/XMLSchema">
<property>
<reference>####</reference>
...
<images>
<image url="https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_JUxtL~PunupG3r34QY7hcc7wMtgouw9c1H6DUbVNANjxM_Zg--.jpg">A2970_10776141.jpg</image>
<image url="https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_AwVzHs_Ajc3bPh6tAooCEbZkq_ZYbRT5eAjUXsq3Znh_f~Vw--.jpg">A2970_10776142.jpg</image>
...
<links/>
</property>
<property>
...
</property>
</properties>
My Code
$feed = file_get_contents('test.xml');
$properties = simplexml_load_string($feed);
foreach ($properties as $property) {
var_dump($property->images);
exit;
}
Result
object(SimpleXMLElement)#5 (1) {
["image"]=>
array(19) {
[0]=>
string(18) "A2970_10776141.jpg"
[1]=>
string(18) "A2970_10776142.jpg"
...
}
}
I've also tried:
foreach ($property->images as $image)
{
var_dump($image['url']);
var_dump($image->attributes());
}
$image['url'] outputs NULL
$image->attributes() outputs error about calling attributes() on a non-object
Ideally, var_dumping $property->images would yield:
object(SimpleXMLElement)#5 (1) {
["image"]=>
array(19) {
[0]=>
object(SimpleXMLElement)#6 (1) {
["#attributes"]=>
array(1) {
["url"]=>
string(162) "https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_JUxtL~PunupG3r34QY7hcc7wMtgouw9c1H6DUbVNANjxM_Zg--.jpg"
}
}
[text]=> "A2970_10776141.jpg"
}
...
}
}
I forgot how much I hated SimpleXML. This worked for me:
<?php
$feed = file_get_contents('test.xml');
$properties = simplexml_load_string($feed);
foreach ($properties as $property)
{
foreach($property->images[0] as $image)
{
print($image['url'] . "\n");
}
}
You're not using the correct value for your foreach loop, you should actually be using $property->images->image as it is those elements you want to iterate over. After that you can take your pick of methods to access the url attribute:
$properties = simplexml_load_string($feed);
foreach ($properties as $property) {
foreach ($property->images->image as $image) {
echo $image['url'] . PHP_EOL;
echo $image->attributes()['url'] . PHP_EOL;
}
}
Output:
https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_JUxtL~PunupG3r34QY7hcc7wMtgouw9c1H6DUbVNANjxM_Zg--.jpg
https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_JUxtL~PunupG3r34QY7hcc7wMtgouw9c1H6DUbVNANjxM_Zg--.jpg
https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_AwVzHs_Ajc3bPh6tAooCEbZkq_ZYbRT5eAjUXsq3Znh_f~Vw--.jpg
https://#####.#########.###/imgV1/QGcM5YXB7ITu20usXVas9zwwpfszaQl0S7VJWTlCweLw8h1OJgGrQ8SrQZiKyUwAW5EgBoJga_AwVzHs_Ajc3bPh6tAooCEbZkq_ZYbRT5eAjUXsq3Znh_f~Vw--.jpg
Demo on 3v4l.org
Nested xml attributes are little bit problematic while using php simplexml
child attributes not capturing by simplexml.
But, you can simply use this function. this will recursively get all xml attributes.
function parseXMLtoArray($xml){
$x = simplexml_load_string($xml);
$result = [];
function parse($xml, &$res){
$res['name'] = $xml->getName();
$res['value'] = $xml->__toString();
foreach ($xml->attributes() as $k => $v){
$res['attr'][$k] = $v->__toString();
}
foreach($xml->children() as $child){
parse($child, $res['children'][]);
}
}
parse($x, $result);
return $result;
}
$resArray = parseXMLtoArray($rawXml);
print_r($resArray);

PHP unset object in foreach loop, $key is name instead of iteration number

I need to unset one of the payments objects but with the code I'm using, I can't get it to work right because $k is not the actual iteration key, it is the name of the object Payment.
How do I get the numerical key of the iteration?
// var_dump of object
object(add_nodes)#14 (1) {
["Payments"]=>
object(add_nodes)#15 (1) {
["Payment"]=>
array(2) {
[0]=>
object(add_nodes)#18 (5) {
["PaymentStatus"]=>
string(9) "Succeeded"
["Payer"]=>
string(10) "podve"
["Payee"]=>
string(11) "PitneyBowes"
["PaymentTime"]=>
string(24) "2018-11-09T09:18:27.000Z"
["PaymentAmount"]=>
string(5) "47.73"
}
[1]=>
object(add_nodes)#19 (7) {
["PaymentStatus"]=>
string(9) "Succeeded"
["Payer"]=>
string(10) "podve"
["Payee"]=>
string(14) "jannesmith"
["PaymentTime"]=>
string(24) "2018-11-09T09:18:27.000Z"
["PaymentAmount"]=>
string(6) "102.99"
["ReferenceID"]=>
string(17) "09273450972340987534"
["FeeOrCreditAmount"]=>
string(4) "4.21"
}
}
}
}
The code:
$xml = simplexml_load_string($response, 'add_nodes');
$payments = $obj->Payments;
if(count($payments->Payment) > 1 ) {
foreach($payments->Payment as $k => $v) {
echo $k; // This = Payment, not 0 or 1
if($v->Payee != 'jannesmith') {
unset($payments->Payment[$k]);
}
}
}
Just as an alternative, I've always been partial to DomDocument and XPath, as it's exactly the same as doing DOM traversal and manipulation in JavaScript, Swift, etc. You don't need to learn all the tricky intricacies of a language-specific implementation like SimpleXML.
$response = <<< XML
<?xml version="1.0"?>
<DocRoot>
<Payments>
<Payment>
<PaymentStatus>Succeeded</PaymentStatus>
<Payer>podve</Payer>
<Payee>Pitney Bowes</Payee>
<PaymentTime>2018-11-09T09:18:27.000Z</PaymentTime>
<PaymentAmount>47.73</PaymentAmount>
</Payment>
<Payment>
<PaymentStatus>Succeeded</PaymentStatus>
<Payer>podve</Payer>
<Payee>jannesmith</Payee>
<PaymentTime>2018-11-09T09:18:27.000Z</PaymentTime>
<PaymentAmount>102.99</PaymentAmount>
<ReferenceID>09273450972340987534</ReferenceID>
<FeeOrCreditAmount>4.21</FeeOrCreditAmount>
</Payment>
</Payments>
</DocRoot>
XML;
$doc = new DomDocument;
$doc->loadXML($response);
$xpath = new DomXPath($doc);
$nodes = $xpath->query("/DocRoot/Payments/Payment[not(./Payee='jannesmith')]");
foreach ($nodes as $node) $node->parentNode->removeChild($node);
echo $doc->saveXML();
Output:
<?xml version="1.0"?>
<DocRoot>
<Payments>
<Payment>
<PaymentStatus>Succeeded</PaymentStatus>
<Payer>podve</Payer>
<Payee>jannesmith</Payee>
<PaymentTime>2018-11-09T09:18:27.000Z</PaymentTime>
<PaymentAmount>102.99</PaymentAmount>
<ReferenceID>09273450972340987534</ReferenceID>
<FeeOrCreditAmount>4.21</FeeOrCreditAmount>
</Payment>
</Payments>
</DocRoot>

Convert XML file to an array

I try to convert XML file to an array in PHP. However, when reading the first array, it is not in form of key and value array.
Is there any way to convert the first data in form of Key and Value? Thanks in advance.
readXML.php
function convertXMLFileToArray()
{
$xml_file = 'customers.xml';
$array_name = 'customer';
//Check whether the file exist
if(file_exists($xml_file)){
//Read the data from xml file
$dt = simplexml_load_file($xml_file,null,LIBXML_NOCDATA);
$json = json_encode($dt);
$outer_array = json_decode($json,TRUE);
//Remove outer array
$array = $outer_array[$array_name];
}
else{
$array = null;
}
var_dump($array);
return $array;
}
Case1
customers.xml
<customers>
<customer>
<cid>1</cid>
<name>Adam</name>
<age>20</age>
</customer>
</customers>
Output
array(3) { ["cid"]=> string(1) "1" ["name"]=> string(4) "Adam" ["age"]=> string(2) "20"}
Case2
customers.xml
<customers>
<customer>
<cid>1</cid>
<name>Adam</name>
<age>20</age>
</customer>
<customer>
<cid>2</cid>
<name>David</name>
<age>23</age>
</customer>
</customers>
Output
array(2) {
[0]=> array(3) { ["cid"]=> string(1) "1" ["name"]=> string(4) "Adam"
["age"]=> string(2) "20" }
[1]=> array(3) { ["cid"]=> string(1) "2" ["name"]=> string(4) "David"
["age"]=> string(2) "23" }
}
Here's one option (using simplexml_load_string instead of file):
function getCustomersFromXml($xml, $key = 'customer')
{
$data = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$out = [];
foreach ($data->$key as $item) {
$out[] = (array) $item;
}
return $out;
}
So you load the XML data, loop the customers object and push each customer object cast as an array into your output.
https://eval.in/990764

Getting data from XML

I am struggling with reading XML file using PHP.
The XML I want to use is here:
http://www.gdacs.org/xml/rss.xml
Now, the data I am interested are the "item" nodes.
I created the following function, which gets the data:
$rawData = simplexml_load_string($response_xml_data);
foreach($rawData->channel->item as $value) {
$title = $value->title;
....
this works fine.
The nodes with the "gdcs:xxxx" were slightly more problematic, but I used the following code, which also works:
$subject = $value->children('dc', true)->subject;
Now the problem I have is with the "resources" node,
Basically the stripped down version of it would look like this:
<channel>
<item>
<gdacs:resources>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
</gdacs:resources>
</item>
</channel>
How in this case would I get the resources? I was able to get always just the first resource and only the title of it. What I would like to do is get all the resources items, which have "type" of a particular value and get their URL.
Running through XML the regular path, is , from my experience, slow and excruciating.
Have a look into XPath -> it's a way to extract data from XML through selectors ( similar to CSS selectors )
http://php.net/manual/en/simplexmlelement.xpath.php
You can select elements by their attributes similar to CSS
<?php
$xmlStr = file_get_contents('some_xml.xml');
$xml = new SimpleXMLElement($xmlStr);
$items = $xml->xpath("//channel/item");
$urls_by_item = array();
foreach($items as $x) {
$urls_by_item [] = $x->xpath("//gdacs:resources/gdacs:resource[#type='image']/#url");
}
Consider using the node occurrence of xpath with square brackets [] to align urls with corresponding titles. A more involved modification of #Daniel Batkilin's answer, you can incorporate both data pieces in an associative multidimensional array, requiring nested for loops.
$xml = simplexml_load_file('http://www.gdacs.org/xml/rss.xml');
$xml->registerXPathNamespace('gdacs', 'http://www.gdacs.org');
$items = $xml->xpath("//channel/item");
$i = 1;
$out = array();
foreach($items as $x) {
$titles = $xml->xpath("//channel/item[".$i."]/gdacs:resources/gdacs:resource[#type='image']/gdacs:title");
$urls = $xml->xpath("//channel/item[".$i."]/gdacs:resources/gdacs:resource[#type='image']/#url");
for($j=0; $j<count($urls); $j++) {
$out[$j.$i]['title'] = (string)$titles[$j];
$out[$j.$i]['url'] = (string)$urls[$j];
}
$i++;
}
$out = array_values($out);
var_dump($out);
ARRAY DUMP
array(40) {
[0]=>
array(2) {
["title"]=>
string(21) "Storm surge animation"
["url"]=>
string(92) "http://webcritech.jrc.ec.europa.eu/ModellingCyclone/cyclonesurgeVM/1000226/final/outres1.gif"
}
[1]=>
array(2) {
["title"]=>
string(26) "Storm surge maximum height"
["url"]=>
string(101) "http://webcritech.jrc.ec.europa.eu/ModellingCyclone/cyclonesurgeVM/1000226/final/P1_MAXHEIGHT_END.jpg"
}
[2]=>
array(2) {
["title"]=>
string(12) "Overview map"
["url"]=>
string(64) "http://dma.gdacs.org/saved/gdacs/tc/1000226/clouds_1000226_2.png"
}
[3]=>
array(2) {
["title"]=>
string(41) "Map of rainfall accummulation in past 24h"
["url"]=>
string(70) "http://dma.gdacs.org/saved/gdacs/tc/1000226/current_rain_1000226_2.png"
}
[4]=>
array(2) {
["title"]=>
string(23) "Map of extreme rainfall"
["url"]=>
string(62) "http://dma.gdacs.org/saved/gdacs/tc/1000226/rain_1000226_2.png"
}
[5]=>
array(2) {
["title"]=>
string(34) "Map of extreme rainfall (original)"
["url"]=>
string(97) "http://www.ssd.noaa.gov/PS/TROP/DATA/ETRAP/2015/NorthIndian/THREE/2015THREE.pmqpf.10100000.00.GIF"
}
...

Converting XML into PHP array with JSON is deleting attributes on some elements

I'm currently processing an extensive XML file, to make some of the processing easier I've used the following method as mentioned extensively on stack overflow
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
This has been awesome but going over my code I've noted some instances where attributes on certain elements aren't converting correctly, at this step $json = json_encode($xml);
Here is a stripped down XML example.
<?xml version="1.0"?>
<property>
<landDetails>
<area unit="squareMeter"/>
</landDetails>
<buildingDetails>
<area unit="squareMeter">100</area>
</buildingDetails>
</property>
and here is the output.
Array (
[landDetails] => Array (
[area] => Array (
[#attributes] => Array (
[unit] => squareMeter
)
)
)
[buildingDetails] => Array (
[area] => 100
)
)
As seen above if the element contains any info on that exact node the associated attributes with that element are not processed. This is causing significant data loss between the conversion.
Does anyone know how to solve this issue?
Thanks in advance!
The elements are processed, they are just not being displayed in the case where the node has attributes AND values. In that case, only the values are being displayed.
The json / array conversion you do is not taking that into account, and only keep the to-be displayed values. I'm afraid there is no trick to do that, but here is a function I used when I didn't know how to trickily convert SimpleXML elements (And which is handling the attributes and values separately)
function simplexml_to_array ($xml, &$array) {
// Empty node : <node></node>
$array[$xml->getName()] = '';
// Nodes with children
foreach ($xml->children() as $child) {
simplexml_to_array($child, $array[$xml->getName()]);
}
// Node attributes
foreach ($xml->attributes() as $key => $att) {
$array[$xml->getName()]['#attributes'][$key] = (string) $att;
}
// Node with value
if (trim((string) $xml) != '') {
$array[$xml->getName()][] = (string) $xml;
}
}
$xml = simplexml_load_string($xml);
simplexml_to_array($xml, $arr);
var_dump($arr);
Output :
array(1) {
["property"]=>
array(2) {
["landDetails"]=>
array(1) {
["area"]=>
array(1) {
["#attributes"]=>
array(1) {
["unit"]=>
string(11) "squareMeter"
}
}
}
["buildingDetails"]=>
array(1) {
["area"]=>
array(2) {
["#attributes"]=>
array(1) {
["unit"]=>
string(11) "squareMeter"
}
[0]=>
string(3) "100"
}
}
}
}

Categories