php SimpleXML get full namespace attributes [duplicate] - php

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;

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"/>

Add xml-stylesheet tag simpleXML php

Hy guys this is my simple code:
$xml = new SimpleXMLElement('<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com"/>');
$xml->addAttribute("versione","FPR12");
$FatturaElettronicaHeader = $xml->addChild('FatturaElettronicaHeader',null,'http://dummy.com');
the xml results is:
<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com" versione="FPR12">
<FatturaElettronicaHeader>
<DatiTrasmissione>
....
How can add at the top of my xml "xml-stylesheet"?
<?xml-stylesheet type="text/xsl" href="fatturapa_v1.2.xsl" ?>
SimpleXML isn't very good at doing anything other than simple things (think that's were the name is very apt). The only way I can think of doing it is to use DOMDocument, which provides a richer API and you should be able to do it as follows...
$xmlD = new DOMDocument( "1.0", "ISO-8859-15" );
$xmlD->appendChild($xmlD->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="fatturapa_v1.2.xsl"'));
$xmlD->appendChild($xmlD->importNode(dom_import_simplexml($xml)));
echo $xmlD->saveXML();
This creates a new DOMDocument instance and then adds a few things. First it uses createProcessingInstruction() to add the processing instruction for the style sheet. Then it imports the existing contents of your SimpleXML document (in $xml) and appends this to the end. The echo should give you a document something like...
<?xml version="1.0" encoding="ISO-8859-15"?>
<?xml-stylesheet type="text/xsl" href="fatturapa_v1.2.xsl"?>
<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com" versione="FPR12"/>

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

PHP SimpleXMLElement addAttribute namespaces syntax

I'm working with SimpleXMLElement for the first time and need to generate a line in my XML as follows:
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
I haven't used addAttribute with namespaces before and can't get the correct syntax working here - I've started with this:
$node = new SimpleXMLElement('< Product ></Product >');
$node->addAttribute("xmlns:", "xsd:", 'http://www.w3.org/2001/XMLSchema-instance');
but can't work out how to correct this for the appropriate syntax to generate the desired output?
solution 1: add a prefix to the prefix
<?php
$node = new SimpleXMLElement('<Product/>');
$node->addAttribute("xmlns:xmlns:xsi", 'http://www.w3.org/2001/XMLSchema-instance');
$node->addAttribute("xmlns:xmlns:xsd", 'http://www.w3.org/2001/XMLSchema');
echo $node->asXML();
output:
<?xml version="1.0"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
note: this is a workaround and actually doesn't set the namespace for the attribute, but just quite enough if you are going to echo / save to file the result
solution 2: put namespace directly in the SimpleXMLElement constructor
<?php
$node = new SimpleXMLElement('<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>');
echo $node->asXML();
output is the same as in solution 1
solution 3 (adds additional attribute)
<?php
$node = new SimpleXMLElement('<Product/>');
$node->addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");
$node->addAttribute("xmlns:xsd", 'http://www.w3.org/2001/XMLSchema', "xmlns");
echo $node->asXML();
output adds additional xmlns:xmlns="xmlns"
<?xml version="1.0"?>
<Product xmlns:xmlns="xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>

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

Categories