I'm trying to loop through an XML document and get out the details of each item.
I manage to get into a single item like this and print its values:
foreach($xml->children() as $games){
echo $games->item->title;
}
But it doesn't loop through all the values.
My instinct to loop through says it should look something like this:
foreach($xml->children()->item as $games){
echo $games->title;
}
But this doesn't return anything.
Example of XML:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>feed EUR</title>
<link>https://www.google.com/</link>
<description>Lorem ipsum</description>
<item>
<g:id>99f3a672-c54a-11e8-83c9-186590d66063</g:id>
<title>7 Days to Die Steam Key GLOBAL</title>
</item>
<item>
<g:id>9aacf9ec-c54a-11e8-9925-186590d66063</g:id>
<title>A Hat in Time Steam Key GLOBAL</title>
</item>
<item>
Children of root <rss> node are <channel>, so you can iterate over them:
foreach ($xml->channel as $channel) {
echo ($channel->title);
}
Related
I know that this questions has been asked before, but I cannot make it work. I'm using simplexml and xpath in a PHP file. I need to get text from a node including the text in its child nodes. So, the results should be:
Mr.Smith bought a white convertible car.
Here is the xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test9.xsl"?>
<items>
<item>
<description>
<name>Mr.Smith bought a <car>white</car> <car>convertible</car> car.</name>
</description>
</item>
</items>
The php that's not working is:
$text = $xml->xpath('//items/item/description/name');
foreach($text as &$value) {
echo $value;
}
Please help!
To get the node value with all its child elements, you can use DOMDocument, with C14n():
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test9.xsl"?>
<items>
<item>
<description>
<name>Mr.Smith bought a <car>white</car> <car>convertible</car> car.</name>
</description>
</item>
</items>
XML;
$doc = new DOMDocument;
$doc->loadXML($xml);
$x = new DOMXpath($doc);
$text = $x->query('//items/item/description/name');
echo $text[0]->C14n(); // Mr.Smith bought a white convertible car.
Demo
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
I've got an url that return an xml but I have some problem to extract "link" element.
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<item>
<id>123</id>
<title>my title</title>
<link>
http://example.org
</link>
</item>
</channel>
</rss>
I need to test it with
Symfony\Component\DomCrawler\Crawler
These are my tests:
$crawler = $this->client->get('/my-feed');
$items = $crawler->filterXPath('//channel/item');
$this->assertGreaterThanOrEqual(1, $items->count()); // ok pass
// ...
$titles = $items->filterXPath('//title')->extract(array('_text'));
$this->assertContains("my title", $titles); // ok pass
// ...
$links = $items->filterXPath('//link')->extract(array('_text'));
$this->assertContains("example.org", $links); // KO!!! don't pass
var_dump($links); // empty string
"link" is a reserved word?
Your XML is broken:
you don't have a closing channel node </channel>
you don't have a closing rss node </rss>
Here is corrected XML :
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<item>
<id>123</id>
<title>my title</title>
<link>http://example.org</link>
</item>
</channel>
</rss>
Then, ->extract() returns An array of extracted values. So you shouldn't directly try to see its contain but get the first element and do your test:
$this->assertContains("my title", $titles[0]);
// ...
$this->assertContains("example.org", $links[0]);
Here is the XML that I am working on :
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:noo="http://www.myscheme.com/schema">
<channel>
<item>
<title>A Simple Title</title>
<noo:subcategory>the sub category</noo:subcategory>
<noo:relatedInfos>
<noo:teams>
<noo:team id="3">New York</noo:team>
<noo:team id="4">Las Vegas</noo:team>
</noo:teams>
</noo:relatedInfos>
</item>
</channel>
</rss>
I am doing this php code to get the two "team" but it does not work ($xml has the previous content) :
$xml_datas = simplexml_load_string($xml);
foreach($xml_datas->channel->item as $item){
$noo = $item->children('noo');
echo $noo->team;
}
Do you have any idea why it is not working ?
Thanks
See if this helps:
<?php // RAY_temp_userco.php
error_reporting(E_ALL);
$xml = <<<ENDXML
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:noo="http://www.myscheme.com/schema">
<channel>
<item>
<title>A Simple Title</title>
<noo:subcategory>the sub category</noo:subcategory>
<noo:relatedInfos>
<noo:teams>
<noo:team id="3">New York</noo:team>
<noo:team id="4">Las Vegas</noo:team>
</noo:teams>
</noo:relatedInfos>
</item>
</channel>
</rss>
ENDXML;
$obj = simplexml_load_string($xml);
$ns = $obj->getNamespaces(TRUE);
foreach($obj->channel->item as $item){
$noo = $item->children($ns['noo']);
var_dump($noo);
}
"noo" is just a local alias for that namespace, and the ->children() method (and most XML handling functions) want to know its actual global identifier, which is the URI in the xmlns attribute.
You need to either specify the full identifier of the namespace (i.e. ->children('http://www.myscheme.com/schema')) or set the optional second parameter to tell SimpleXML to look up the prefix (->children('noo', true). The second may be more readable, but it will break if a future document has the same schema, but gives the namespace a different local alias.
Additionally, the team nodes aren't directly under the item node, so you need to traverse further to get them:
// Give the namespace a readable name that won't change
define('NS_NOO', 'http://www.myscheme.com/schema');
$xml_datas = simplexml_load_string($xml);
foreach($xml_datas->channel->item as $item){
$teams = $item->children(NS_NOO)->relatedInfo->teams;
echo $teams->team[0];
}
I have an xml document with the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>
I would like to be able to search for a node value, such as the value of 1 for the id field. Then, once that node is found, select the parent node, which would be < item > and insert a new child within.
I know the concept of using dom document, but not sure how to do it in this instance.
This should be a start:
$dom = new DOMDocument;
$dom->loadXML($input);
$ids = $dom->getElementsByTagName('id');
foreach ($ids as $id) {
if ($id->nodeValue == '1') {
$child = $dom->createElement('tagname');
$child->appendChild($dom->createTextNode('some text'));
$id->parentNode->appendChild($child);
}
}
$xml = $dom->saveXML();
or something close to it.
You can do the same thing in a simpler way. Instead of looking for an <id/> node whose value is 1 then selecting its parent, you can reverse the relation and look for any node which has an <id/> child whose value is 1.
You can do that very easily in XPath, and here's how to do it in SimpleXML:
$items = simplexml_load_string(
'<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>'
);
$nodes = $items->xpath('*[id = "1"]');
$nodes[0]->addChild('new', 'value');
echo $items->asXML();