Issue parsing namespaces using PHP SimpleXML - php

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

Related

xpath with simplexml not able to access nested element

I have an xml like so:
<?xml version="1.0" encoding="UTF-8"?>
<foo SeqNum="1">
<bar>1234</bar>
</foo>
<foo SeqNum="20">
<bar>6789</bar>
</foo>
and I'm trying to get the value 6789 with this query:
$xml = "<?xml version="1.0" encoding="UTF-8"?>
<foo SeqNum="1">
<bar>1234</bar>
</foo>
<foo SeqNum="20">
<bar>6789</bar>
</foo>";
$simple = new SimpleXMLElement($xml);
$result = $simple->xpath('//*[#SeqNum="20"]/bar/'); // result gives me nothing
So I tried to just get the parent like so
$result = $simple->xpath('//*[#SeqNum="20"]')[0]->asXML();
which gives me:
<foo SeqNum="20">
<bar>6789</bar>
</foo>
So I'm almost there but am really stuck about what I'm not understanding. Thank you!
Here are several mistakes in the question. The XML needs a root element and the trailing / breaks the expression. The literal quotes need to be changed to single quotes (or all the inner double quotes need to be escaped.)
Fixed example:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<foo>
<foo SeqNum="1">
<bar>1234</bar>
</foo>
<foo SeqNum="20">
<bar>6789</bar>
</foo>
</foo>';
$simple = new SimpleXMLElement($xml);
$result = $simple->xpath('//*[#SeqNum="20"]/bar');
var_dump((string)$result[0]);
Output:
string(4) "6789"
With Namespaces
If your XML is using namespaces you will have to define an alias/prefix for this namespace URI and use that in the Xpath expression.
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8" ?>
<p:foo xmlns:p="http://www.example.com">
<p:foo SeqNum="1">
<p:bar>1234</p:bar>
</p:foo>
<p:foo SeqNum="20">
<p:bar>6789</p:bar>
</p:foo>
</p:foo>
XML;
$simple = new SimpleXMLElement($xml);
$simple->registerXpathNamespace('e', 'http://www.example.com');
$result = $simple->xpath('//*[#SeqNum="20"]/e:bar');
var_dump((string)$result[0]);
The example uses a different alias for the expression to show that the document and the expression are separate - only the namespace URI has to match.
Namespaces have to be unique so they are defined with an URI (a superset of URL). Because that would get messy aliases are used in node names. The following 3 elements all can be read as {http://www.example.com}bar.
<p:bar xmlns:p="http://www.example.com"/>
<e:bar xmlns:e="http://www.example.com"/>
<bar xmlns="http://www.example.com"/>

PHP get specific data from xml file

This is XML file.
<?xml version="1.0" encoding="utf-8"?>
<UW xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<UWdata>
<List>
<IdProduct>1</IdProduct>
<ProductName>product</ProductName>
<ProductNameDE>product</ProductNameDE>
<ProductNameEN>product</ProductNameEN>
<Uf>1</Uf>
<PSIg>1</PSIg>
<Ug>1</Ug>
</List>
</UWdata>
</UW>
$lines_array=file($url);
$lines_string=implode('',$lines_array);
$xml=simplexml_load_string($lines_string) or die("Error: Cannot create object");
I try with this
echo $xml->UWdata[1]->ProductName;
But it doesn't return anything.I want to return Product name.
Sample code, Use simplexml_load_string
<?php
$a = '<?xml version="1.0" encoding="utf-8"?>
<UW xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<UWdata>
<List>
<IdProduct>1</IdProduct>
<ProductName>product</ProductName>
<ProductNameDE>product</ProductNameDE>
<ProductNameEN>product</ProductNameEN>
<Uf>1</Uf>
<PSIg>1</PSIg>
<Ug>1</Ug>
</List>
</UWdata>
</UW>';
$xml=simplexml_load_string($a) or die("Error: Cannot create object");
echo ($xml->UWdata->List->ProductName);
?>
When you load the xml file using the php simplexml_load_file function to a variable. The veritable becomes an object.
<?php
$xml=simplexml_load_file("/path/to/the/file.xml");
?>
So, in your case, the $xml variable becomes a multi-level object where every elements of xml file are key of the object. Like: UWdata.
So, as $xml is a multi-level object, to access the element under UWdata, under List under ProductName, you have to code like bellow.
echo $xml->UWdata->List->ProductName."<br>";
Here,
UWdata is the key of $xml object.
List is the key of UWdata.
ProductName is the key of List.
Finally, you will get the value of key element ProductName = product
I modified your script and put the xml in an external file called testxml.xml, as it should be. Always separate the function and the data it's supposed to handle. I used your xml like this:
<?xml version="1.0" encoding="utf-8"?>
<UW xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<UWdata>
<List>
<IdProduct>1</IdProduct>
<ProductName>productTEST</ProductName>
<ProductNameDE>product</ProductNameDE>
<ProductNameEN>product</ProductNameEN>
<Uf>1</Uf>
<PSIg>1</PSIg>
<Ug>1</Ug>
</List>
</UWdata>
</UW>
And with the following script it returns productTEST only.
$xmlstr = file_get_contents('./testxml.xml');
$xml = simplexml_load_string($xmlstr);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
echo $array['UWdata']['List']['ProductName'];
Hope this helps.
//edit:
While I do not know your project, you might want to take a foreach-approach if it is possible for your xml to contain more than one List element

Append / Clone nodes in xml File with help of php

I am beginner in php and currently working on php-xml parsing in which i am not getting how should i append node with specific node having different value in same xml file.
Explanation :
Since i don't have enough data so i need to duplicate nodes (here it is test node) so that i can increase my file size and then work on parsing.
In short i need to generate big xml file with exisitng single node.
Current Xml File :
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
Expected Output:
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">15000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
**My Approach **
$xmlString = simplexml_load_string(file_get_contents('./PhpXmlFile.xml'));
$xmlString = $xmlString->xpath('/Testings/Test/');
if ( $xmlString && is_array( $xmlString ) ) {
// since it IS an array, set to the first element of the array
$xmlString = $xmlString[0];
// And NOW we can append
$xmlString = $xmlString->addChild('Test','');
}
$dom = new DOMDocument("1.0");
$dom->preserveWhiteSpace = true;
$dom->formatOutput = true;
$dom->loadXML($xmlString->saveXML());
Thanks in advance!!
Here we are using DOMDocument for cloning a child node. Here for an example i am using nodeValue as 1000 you can change it to the value you want.
Here in a below code we are using $domDocument->getElementsByTagName("AreaPrice")->item(2)->nodeValue=1000; for item no 2 because after appending the a clone node, There will be four elements with name AreaPrice.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$string = <<<HTML
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order class='sas'>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</AreaPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</AreaPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
HTML;
$domDocument = new DOMDocument();
$domDocument->loadXML($string);
$results=$domDocument->getElementsByTagName("Test");
$clonedNode=$results->item(0)->cloneNode(true);
$results->item(0)->parentNode->appendChild($clonedNode);
$domDocument->getElementsByTagName("AreaPrice")->item(2)->nodeValue=1000;//change the value you want.
echo $domDocument->saveXML();

php SimpleXML get full namespace attributes [duplicate]

I'd like to get the content of the attribute xsi:schemaLocation. It's works perfectly with getElementsByTagName in php (and foreach after) but it's ugly, right ?
How to get the same content with a simple Xpath query ?
Here a short example of the xml content :
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
...
</gpx>
Thanks!
Typically you need to register the namespaces you want to use with the XPath library first. Then you can query the attribute by including namespace prefix along with the name.
So let's assume you're using DOMXPath, you might register the following namespaces:
$xpath = new DOMXPath($doc);
$xpath->registerNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance");
$xpath->registerNamespace("gpx", "http://www.topografix.com/GPX/1/0");
And then you can query the schemaLocation attribute with something like this:
$xpath->query("/gpx:gpx/#xsi:schemaLocation",$doc);
Using the SimpleXMLElement class you can easily get the attribute xsi:schemaLocation's value:
<?php
$xml = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
</gpx>
XML;
$sxe = new SimpleXMLElement($xml);
$schemaLocation = $sxe->attributes('xsi', true)->schemaLocation;
echo (string) $schemaLocation;

PHP SimpleXMLElement problems with xml node

I want to create an XML with the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<content>
<!-- content goes here -->
</content>
I originally created the xml node like this:
$xml = new SimpleXMLElement('<xml/>');
$content = $xml->addChild('content');
// add data to content
but that doesn't allow for adding attributes to the xml node, so now I do this:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>'
.'<content></content>');
For some reason it doesn't work without adding the content node, but whatever, it gets the structure right.
Now, how do I assign the content node to a variable like I did above, so I can add data to it?
In your case the $xml variable is equal to the content node just try the following:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>'
.'<content></content>');
$xml->addAttribute('Attribute', 'value');
$xml->addChild('node_name', 'value');
echo $xml->asXML();
this should print
<?xml version="1.0" encoding="UTF-8"?>
<content Attribute="value"><node_name>value</node_name></content>
E.g.
<?php
$content = new SimpleXMLElement('<content />');
$content['attr']='value';
echo $content->asXML();
prints
<?xml version="1.0"?>
<content attr="value"/>
--- edit:
To keep the encoding=utf-8:
$content = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
<content />');
An XML document must have at least one element. That is the document element. In your question this is the content element.
You can create a SimpleXMLElement of it by just instantiating it with this minimum string:
$xml = new SimpleXMLElement('<content/>');
The variable $xml then represents that element. You can then...
... add attributes: $xml['attribute'] = 'value';
... set the content-text: $xml[0] = 'text';
... add child-elements: $xml->child = 'value';
This exemplary line-up then would have created the following XML (beautified, also: online demo):
<?xml version="1.0"?>
<content attribute="value">
text
<child>value</child>
</content>

Categories