PHP : how to parse XML with nested xpath elements - php

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];
}

Related

Issue parsing namespaces using PHP SimpleXML

I have this xml content :
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ns3:searchResult total="1" xmlns:ns5="ers.ise.cisco.com" xmlns:ers-v2="ers-v2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns3="v2.ers.ise.cisco.com">
<ns3:resources>
<ns5:resource id="42e98860-cb88-11e5-9b0c-000c29c658fa" name="11:22:33:44:55:66">
<link rel="self" href="https://1.2.3.4:9060/ers/config/endpoint/42e98860-cb88-11e5-9b0c-000c29c658fa" type="application/xml"/>
</ns5:resource>
</ns3:resources>
</ns3:searchResult>
i need to get the value of the ns5:resource id value (42e98860-cb88-11e5-9b0c-000c29c658fa), but the use of namespaces in every node has me confused, i tried using the $xml->children('ns5',true)->resource->id and everything i try just gives me empty simplexml objects.
Any suggestions?
I think you can use this xpath expression:
$elements =
$xml->xpath('/ns3:searchResult/ns3:resources/ns5:resource');
xpath will return an array and you can take the first item from that array. That item is of type SimpleXMLElement and you can get your id from its attributes.
$source = <<<SOURCE
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ns3:searchResult total="1" xmlns:ns5="ers.ise.cisco.com" xmlns:ers-v2="ers-v2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns3="v2.ers.ise.cisco.com">
<ns3:resources>
<ns5:resource id="42e98860-cb88-11e5-9b0c-000c29c658fa" name="11:22:33:44:55:66">
<link rel="self" href="https://1.2.3.4:9060/ers/config/endpoint/42e98860-cb88-11e5-9b0c-000c29c658fa" type="application/xml"/>
</ns5:resource>
</ns3:resources>
</ns3:searchResult>
SOURCE;
$xml = simplexml_load_string($source);
$elements = $xml->xpath('/ns3:searchResult/ns3:resources/ns5:resource');
$element = $elements[0];
echo $element->attributes()->id->__toString();
Will result in:
42e98860-cb88-11e5-9b0c-000c29c658fa

How to generate namespace prefixed xml elements using SimpleXMLElement in PHP

I'm trying to generate a RSS feed using PHP SimpleXMLElement, the problem is that i need to prefix elements and can't find a way to do this using the SimpleXMLElement class.
I've tried using $item->addChild('prefix:element', 'value') but in the result xml it strips the prefix, any idea why this happens ?.
I wonder if there is a way to solve this using the SimpleXMLElement or any other cleaner way than just echoing the XML.
For clarification, this is my PHP code:
$xml = new SimpleXMLElement('<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0"/>');
$channel = $xml->addChild('channel');
$channel->addChild('title', 'Text');
$channel->addChild('link', 'http://example.com');
$channel->addChild('description', 'An example item from the feed.');
foreach($this->products as $product) {
$item = $channel->addChild('item');
foreach($product as $key => $value)
$item->addChild($key, $value);
}
return $xml->asXML();
And this is the example XML i'm trying to generate:
<?xml version="1.0"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<title>Test Store</title>
<link>http://www.example.com</link>
<description>An example item from the feed</description>
<item>
<g:id>DB_1</g:id>
<g:title>Dog Bowl In Blue</g:title>
<g:description>Solid plastic Dog Bowl in marine blue color</g:description>
...
</item>
...
Thanks in advance
You need to pass the namespace uri of the prefix to add child element with prefix :
$item->addChild($key, $value, 'http://base.google.com/ns/1.0');
eval.in demo :
$xml = new SimpleXMLElement('<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0"/>');
$channel = $xml->addChild('channel');
$channel->addChild('title', 'Text');
$channel->addChild('link', 'http://example.com');
$channel->addChild('description', 'An example item from the feed.');
$item = $channel->addChild('item');
$item->addChild('g:foo', 'bar', 'http://base.google.com/ns/1.0');
print $xml->asXML();

how to get a node name from an unknown node via SimpleXML

For example I have 2 types of nodes in my xml file:
1) <book>
2) <author>
A variable named $node points to specific node(of unknown type).
How can I access this node's name? It must be something like this:
if($node->name()=="book")
process_book($node);
else
process_author;
SimpleXMLElement has a getName() method:
echo $node->getName();
Assumption: $node is a SimpleXMLElement object.
I may be missing something, but here is a simlpe solution. Change simplexml_load_string to simplexml_load_file if your using a file.
$xml_string = <<<XML
<root>
<item>
<book>Book 1</book>
<author>Author 1</author>
</item>
<item>
<book>Book 2</book>
<author>Author 2</author>
</item>
<item>
<book>Book 3</book>
<author>Author 3</author>
</item>
</root>
XML;
$xml = simplexml_load_string($xml_string);
foreach($xml->item as $node){
if(isset($node->book)){
process_book($node);
}
}

Parse XML in PHP by specific attribute

I need to get <name> and <URL> tag's value where subtype="mytype".How can do it in PHP?
I want document name and test.pdf path in my result.
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
Use SimpleXML and XPath, eg
$xml = simplexml_load_file('path/to/file.xml');
$items = $xml->xpath('//item[#subtype="mytype"]');
foreach ($items as $item) {
$name = (string) $item->name;
$url = (string) $item->url;
}
PHP 5.1.2+ has an extension called SimpleXML enabled by default. It's very useful for parsing well-formed XML like your example above.
First, create a SimpleXMLElement instance, passing the XML to its constructor. SimpleXML will parse the XML for you. (This is where I feel the elegance of SimpleXML lies - SimpleXMLElement is the entire library's sole class.)
$xml = new SimpleXMLElement($yourXml);
Now, you can easily traverse the XML as if it were any PHP object. Attributes are accessible as array values. Since you're looking for tags with specific attribute values, we can write a simple loop to go through the XML:
<?php
$yourXml = <<<END
<?xml version="1.0" encoding="UTF-8"?>
<test>
<required>
<item type="binary">
<name>The name</name>
<url visibility="restricted">c:/temp/test/widget.exe</url>
</item>
<item type="document" subtype="mytype">
<name>document name</name>
<url visiblity="visible">c:/temp/test.pdf</url>
</item>
</required>
</test>
END;
// Create the SimpleXMLElement
$xml = new SimpleXMLElement($yourXml);
// Store an array of results, matching names to URLs.
$results = array();
// Loop through all of the tests
foreach ($xml->required[0]->item as $item) {
if ( ! isset($item['subtype']) || $item['subtype'] != 'mytype') {
// Skip this one.
continue;
}
// Cast, because all of the stuff in the SimpleXMLElement is a SimpleXMLElement.
$results[(string)$item->name] = (string)$item->url;
}
print_r($results);
Tested to be correct in codepad.
Hope this helps!
You can use the XML Parser or SimpleXML.

PHP namespace simplexml problems

Evening guys.
Firstly to say, I have read How do I parse XML containing custom namespaces using SimpleXML?.
I'm parsing an XML document from a source not mind, and they use a custom namespace.
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:moshtix="http://www.moshtix.com.au">
<channel>
<item>
<link>qweqwe</link>
<moshtix:genre>asdasd</moshtix:genre>
...
For example. When I parse using SimpleXML, none of the mostix: namespace elements are on show or accessible. Probably a really simple solution, but any ideas guys?
Usually, people use children().
$rss = simplexml_load_string(
'<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:moshtix="http://www.moshtix.com.au">
<channel>
<link>qweqwe</link>
<moshtix:genre>asdasd</moshtix:genre>
</channel>
</rss>'
);
foreach ($rss->channel as $channel)
{
echo 'link: ', $channel->link, "\n";
echo 'genre: ', $channel->children('moshtix', true)->genre, "\n";
}

Categories