Select especific nodes in XML (Loop) - php

I can't access only one node of an xml
<destinos>
<destino>
<programas>
<item>
<location>Spain</location>
...more content
</item>
<item>
<location>USA</location>
...more content
</item>
</programas>
</destino>
<destino>
<programas>
<item>
<location>France</location>
...more content
</item>
<item>
<location>Brasil</location>
...more content
</item>
</programas>
</destino>
</destinos>
I need:
<item>
<location>Spain</location>
...more content
</item>
<item>
<location>USA</location>
...more content
</item>
<item>
<location>France</location>
...more content
</item>
<item>
<location>Brasil</location>
...more content
</item>
i tried:
header('Content-Type: application/xml');
foreach ($xml->destinos->destino->programas as $resultado){
echo $resultado->asXML();
}
or
$xml = simplexml_load_string($string);
$items = $xml->xpath("//destino/programas");
header('Content-Type: application/xml');
foreach ($items as $personaje) {
echo $personaje->asXML();
}
But I only get the first two "item" of "program" or four elements but error in xml in the second example.
Thanks for the help, I have looked for solutions but I have not been able to find any that will help me solve this problem.

This is a bit of a fudge as it 'manually' adds in a root element. The main loop uses XPath to find all of the <item> tags and then just outputs the content.
header('Content-Type: application/xml');
$xml = simplexml_load_string($string);
echo "<root>";
foreach ($xml->xpath("//item") as $item){
echo $item->asXML();
}
echo "</root>";

Related

PHP - Access Item from XML with xpath()

I want to get the ISBN number of a book from an Amazon XML File. I already checked other posts and tried to solve the problem with them but without any success. The $xml looks like:
<itemlookupresponse>
<items>
<item>
<itemattributes>
<studio>Pottermore from J.K. Rowling</studio>
<eisbn>9781781100769</eisbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen Verlag GmbH</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
</items>
</itemlookupresponse>
I want to get the items, where the ISBN equals 3551551677. For that reason, I used the following command, which unfortunately returns an empty array.
$item = $xml->xpath('//items/item[itemattributes/isbn=3551551677]');
I would be glad, if someone could help me and explain, what I made wrong.
XML and XPath are case-sensitive. Amazon's XML is not all lowercase, despite what you've posted in your question. Adjust your XPath to match the exact case used in Amazon's actual XML.
Note also that if there are namespaces involved in the actual XML, those too must be accounted for in your XPath. See How does XPath deal with XML namespaces?
You didn't show something important (namespaces?) because this code works for me:
$string = <<<XML
<itemlookupresponse>
<items>
<item>
<itemattributes>
<studio>Pottermore from J.K. Rowling</studio>
<eisbn>9781781100769</eisbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen Verlag GmbH</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
</items>
</itemlookupresponse>
XML;
$xml = new SimpleXMLElement($string);
/* Поиск <a><b><c> */
$items = $xml->xpath('//items/item[ ./itemattributes/isbn[.="3551551677"] ]');
//$items = $xml->xpath('//items/item[itemattributes/isbn=3551551677]');
echo "Result size: " . count($items) . "\n";
foreach ( $items as $item) {
echo $item->asXML() . "\n";
}

How can I retrieve specific XML tag names?

The feed above returns an XML document. I can successfully retrieve tag names like title,description and link using these codes
$xml = file_get_contents($feed_url);
$xml = trim($xml);
$xmlObject = new SimpleXmlElement($xml);
foreach ($xmlObject->channel->item as $item) {
$title = strip_tags($item->title);
$description = strip_tags($item->description);
}
How can I get <a10:updated> ?
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>title/title>
<link>link</link>
<description>news</description>
<item>
<guid isPermaLink="true">link</guid>
<link>link</link>
<title>Tiele</title>
<description>Descr</description>
<enclosure url="image" type="image/jpeg"/>
<a10:updated>2017-05-07T09:14:00+03:00</a10:updated>
</item>
</channel>
</rss>
Here we are using DOMDocument for extracting data from a tag.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$xml='<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>title</title>
<link>link</link>
<description>news</description>
<item>
<guid isPermaLink="true">link</guid>
<link>link</link>
<title>Tiele</title>
<description>Descr</description>
<enclosure url="image" type="image/jpeg"/>
<a10:updated>2017-05-07T09:14:00+03:00</a10:updated>
</item>
</channel>
</rss>';
$xmlObject = new DOMDocument();
$xmlObject->loadXML($xml);
$result=$xmlObject->getElementsByTagNameNS("http://www.w3.org/2005/Atom", "*");
print_r($result->item(0)->textContent);
Output:
2017-05-07T09:14:00+03:00
You're looking at a different XML namespace there. You can use curly brackets to access it:
$a10 = $item->{'a10:updated'}

Foreach loop through XML tags named tag-1, tag-2, tag-3

How can one loop through XML structure with tags named like
<response>
<tag-1>
<item>
<id>106</id>
<title>DG</title>
</item>
<item>
<id>105</id>
<title>AC</title>
</item>
</tag-1>
<tag-2>
<item>
<id>1</id>
<title>DjG</title>
</item>
<item>
<id>15</id>
<title>AoC</title>
</item>
</tag-2>
</response>
So I load xml with simplexml_load_file, then I tried with xml->children().
$xml = simplexml_load_file("data.xml");
foreach($xml->children() as $kat);
{
var_dump($kat);
}
This has only returned the last element. So I can not loop through all of the tag-* elements.
Any help how to loop through all tags named tag-* will be very appreciated

Remove one tag and all of it's child nodes of a xml using php

i'm trying to remove one item from a xml with all of it's child nodes but when i excecute following php only the child nodes will be removed.
following is my php
<?php
header('Content-Type: text/xml');
$doc = new DOMDocument('1.0');
$url = '../../data/auction.xml';
$itemNo ="0";
$xml=simplexml_load_file($url);
foreach($xml->xpath('/items/item[itemNumber="'.$itemNo.'"]')as $child)
{
unset($child[0]);
//$child->parentNode->removeChild($node);
}
print $xml->asXML();
?>
the original XML
<?xml version="1.0"?>
<items>
<item>
<itemNumber>0</itemNumber>
<itemName>item1</itemName>
<category>Phones</category>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Actual output
<items>
<item>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Desired output
<items>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Please tell me what i'm doing wrong

Replacing innertext of XML node using PHP DOMDocument

I want to replace innertext of a XML node my XML file named test.xml is
<?xml version="1.0" encoding="utf-8"?>
<ads>
<loop>no</loop>
<item>
<description>Description 1</description>
</item>
<item>
<description>Text in item2</description>
</item>
<item>
<description>Let play with this XML</description>
</item>
</ads>
I want to change the value of loop and description tag both,
and it should be saved in test.xml like:
<?xml version="1.0" encoding="utf-8"?>
<ads>
<loop>yes</loop>
<item>
<description>Description Changing Here</description>
</item>
<item>
<description>Changing text in item2</description>
</item>
<item>
<description>We will play later</description>
</item>
</ads>
I tried code in PHP:
<?
$file = "test.xml";
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$dom=new DOMDocument();
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
$dom->loadXML($str) or die("Error");
//$dom->load("items.xml");
$root=$dom->documentElement; // This can differ (I am not sure, it can be only documentElement or documentElement->firstChild or only firstChild)
$loop=$root->getElementsByTagName('loop')->item(0);//->textContent;
//echo $loop;
if(trim($loop->textContent)=='no')
{
echo 'ok';
$root->getElementsByTagName('loop')->item(0)->nodeValue ='yes';
}
echo "<xmp>NEW:\n". $dom->saveXML() ."</xmp>";
?>
I tried only for loop tag.I don't know how to replace nodevalue in description tag.
When I run this page it shows output like:
ok
NEW:
<?xml version="1.0" encoding="utf-8"?>
<ads>
<loop>yes</loop>
<item>
<description>Description 1</description>
</item>
<item>
<description>Changing text in item2</description>
</item>
<item>
<description>Let play with this XML</description>
</item>
</ads>
It gives the value yes in browser but don't save it in test.xml any reason?
So, since you have created DOMDocument you can use DOMXpath. Or keep using getElementsByTagName()
You could do this (but only in that context):
$descriptions = $root->getElementsByTagName('description');
foreach($descriptions as $nodeDesciption)
{
$nodeDesciption->nodeValue ='Your custom value';
}

Categories