SimpleXMLElement and xpath [duplicate] - php

This question already has an answer here:
SimpleXmlElement and XPath, getting empty array()
(1 answer)
Closed 8 years ago.
I have an XML doc similar to:
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:zapi="http://zotero.org/ns/api">
<link rel="up" type="application/atom+xml" href="some link"/>
</entry>
I want the "up" (rel attribute) of the link element, so I do this:
$xml = new SimpleXMLElement($body);
$php_up = $xml->xpath("//link[#rel='up']");
var_dump($php_up); exit;
which just gives me array(0) { }.
What am I doing wrong?

The declaration in the second line of your XML gives two XML namespaces:
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:zapi="http://zotero.org/ns/api">
The first xmlns attribute, with no colon-separated suffix, sets the "default" namespace for the entry element as being http://www.w3.org/2005/Atom, and descendant nodes with no prefix are in that namespace by default. To be able to access these elements with a "default" namespace using XPath, you need to set a namespace using registerXPathNamespace, and then perform your query, prefixing the element you're looking for (link) with the namespace:
$xml->registerXPathNamespace('d', 'http://www.w3.org/2005/Atom');
$php_up = $xml->xpath("//d:link[#rel='up']");
var_dump($php_up);
Output:
array(1) {
[0] =>
class SimpleXMLElement#2 (1) {
public $#attributes =>
array(3) {
'rel' =>
string(2) "up"
'type' =>
string(20) "application/atom+xml"
'href' =>
string(9) "some link"
}
}
}

You don't need XPATH to get the REL attribute. This should be as simple as:
$php_up = $xml->link->attributes()->rel;
Updated: To get the attributes of multiple link elements:
The XML:
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:zapi="http://zotero.org/ns/api">
<link rel="up" type="application/atom+xml" href="some link"/>
<link rel="down" type="application/atom+xml" href="some link"/>
</entry>
The PHP:
$xml = new SimpleXMLElement($body);
foreach ($xml->link as $link) {
$rels[] = (string)$link->attributes()->rel;
}
var_dump($rels); exit;

It's not going to be obvious, but you need to use str_replace on your xmlns :)
$body= str_replace('xmlns=', 'ns=', $body);
Before you call your $xml = new SimpleXMLElement($body);
Here's your eval.in

Related

Unable to get node from simplexml_load_string

I understand this question has been asked, but all solutions I've found have not worked for me.
Given this:
SimpleXMLElement Object
(
[0] =>
<test>
<blah>
<x>
filler
</x>
</blah>
</test>
)
How do I get the <x> value?
I've tried
$doc = simplexml_load_string($xml_response);
print_r($doc->test->blah->x);
print_r($doc[0]->test->blah->x);
print_r($doc->{'0'}->test->blah->x);
print_r((string)$doc->{'0'}->test->blah->x);
print_r((string)$doc[0]->test->blah->x);
print_r((string)$doc->test->blah->x);
Here's the raw xml:
1.0" encoding="UTF-8" ?>
<xxx>
<test>
<blah>
<x>fillertexthere</x>
</blah>
<fillertexthere</Reason>
</test>
</xxx>%
Your SimpleXMLElement contains one string. I think that is because your xml contains < and >.
What you could do is first use htmlspecialchars_decode and then load your string.
(I have removed this line <fillertexthere</Reason> and % from your raw xml)
$xml_response = <<<DATA
<?xml version="1.0" encoding="UTF-8" ?>
<xxx>
<test>
<blah>
<x>fillertexthere</x>
</blah>
</test>
</xxx>
DATA;
$xml_response = htmlspecialchars_decode($xml_response);
var_dump($xml_response);
This will look like:
object(SimpleXMLElement)#1 (1) {
["test"]=>
object(SimpleXMLElement)#2 (1) {
["blah"]=>
object(SimpleXMLElement)#3 (1) {
["x"]=>
string(14) "fillertexthere"
}
}
}
You can echo the value of x like this:
echo $doc->test->blah->x;

PHP: How to extract “content type=”application/xml" nodes from a XML file?

I have a valid XML file (generated from SharePoint) which looks like this (in browser):
Sample XML File
<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="https://www.example.com/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>9913f043-xxxx-xxxx-xxxx-xxxx-xxxx</id>
<title />
<updated>2017-05-23T06:08:01Z</updated>
<entry m:etag=""23"">
<id>Web/Lists(guid'13306095-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx')/Items(1)</id>
<category term="SP.Data.XXXXXXXXXXXXXXXXXXXXX" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'13306095-xxxx-xxxx-xxxx-xxxx-xxxx')/Items(1)" />
<title />
<updated>2017-05-23T06:08:01Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:FileSystemObjectType m:type="Edm.Int32">0</d:FileSystemObjectType>
<d:Id m:type="Edm.Int32">1</d:Id>
<d:ContentTypeId>0x0100B6A3B67BE96F724682CCDC8FBE9D70C2</d:ContentTypeId>
<d:Title m:null="true" />
<d:Topic>How to google?</d:Topic>
<d:Cats m:type="Collection(Edm.Int32)">
<d:element>1</d:element>
<d:element>2</d:element>
<d:element>3</d:element>
<d:element>4</d:element>
<d:element>5</d:element>
<d:element>6</d:element>
<d:element>7</d:element>
</d:Cats>
</m:properties>
</content>
</entry>
<entry>
.
.
</entry>
<entry>
.
.
</entry>
</feed>
(Note: I cut off some repeated nodes here, because it is so long.)
Clearly, we have inner nodes <content type="application/xml"> which also contain data inside.
The Problem (When parsing with PHP)
In PHP, i used this codes to parse (trying to extract it):
$xml = simplexml_load_file("data.xml");
foreach ($xml->entry as $item) {
echo $item->updated . PHP_EOL; // <--- This works!
print_r($item->content); // <--- This doesn't work as expected.
}
.. and then, it is giving me these:
2017-05-23T06:08:01Z
SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => application/xml
)
)
2017-05-23T06:08:01Z
SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => application/xml
)
)
.
.
Question (Help!)
How do i extract (get) the actual data inside those <content type="application/xml"> nodes, please?
Please help. Thank you in advance.
The elements below "content" have a namespace (d:...). I had the same problem a while ago. This should help:
$xml = simplexml_load_file("data.xml");
foreach ($xml->entry as $item) {
echo $item->updated . PHP_EOL;
$ns = $item->content->children('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
print_r($ns->properties);
}
I updated the code. I'm shure print_r($ns->properties) doesn't show the complete sub-elements ... because they are from another namspace. I guess you can then do this:
$nsd = $ns->properties->children("http://schemas.microsoft.com/ado/2007/08/dataservices");
and proccced with the result.
In your example namespaces can be found in the document element:
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
(use the URL between the quotation marks)
d: and m: are used in the document to reference these namespaces.
EDIT: There is another namespace involved. Didn't recognize that. The solution can be atapted. I changed the code a bit.
I had a very similar issue. I was finally able to get my example working with this.
function pre($array){
echo "<pre>";
print_r($array);
echo "</pre>";
}
$record[$count]['id'] = $id->id;
$xmlData = utf8_encode(file_get_contents("https://ucf.uscourts.gov/odata.svc/Creditors(guid'81044f71-fb3c-11e5-ac5b-0050569d488e')"));
$xml = new SimpleXMLElement($xmlData);
$properties = $xml->content->children('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
$fields = $properties->properties->children("http://schemas.microsoft.com/ado/2007/08/dataservices");
pre($fields);
$key = (string)$fields->Key;
$lastName = (string)$fields->LastName;
echo $key. "<br />";
echo $lastName. "<br />";
You would need to replace the Url in file_get_contents, the Key variable and LastName variable with you namespace values that you are looking for and I like to use a pre function to have things show easier. You can remove this part. Hopes this helps someone.

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

Get Child Node XML With DomDocument PHP

I have read instruction of DomDocument PHP, and try to get specific child from xml file, here the example
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<methods>
<index>
<title>User</title>
<meta_description>Description part</meta_description>
<meta_keywords>keywords parts</meta_keywords>
<permissions>permissions part</permissions>
<layout>layout parts</layout>
<css>css parts</css>
</index>
<update>
<title>update part</title>
<permissions>update_user</permissions>
</update>
</methods>
</configuration>
What I want is, let say I want to access permissions value tag of index tag, then how to do that? And how to check if permissions tag is exists on index tag with domdocument php.
Here, what I have done
$xml = new DOMDocument();
$xml->load(__DIR__ . DIRECTORY_SEPARATOR . 'configuration.xml');
$configurations['title'] = $xml->getElementsByTagName('index title')->nodeValue;
print_r($configurations);
The argument of DOMDocument::getElementsByTagName() is a single node name and it always returns a node list. For more complex and flexible expressions you need to use XPath:
$dom = new DOMDocument();
$dom->load(__DIR__ . DIRECTORY_SEPARATOR . 'configuration.xml');
$xpath = new DOMXPath($dom);
$configurations['title'] = $xpath->evaluate('string(//index/title)');
var_dump($configurations);
Output:
array(1) {
["title"]=>
string(4) "User"
}

How to get value of XML tag (which contains namespace) using PHP's simplexml_load_string?

How do I get the value of "TagOne" (i.e. foo) and TagTwo (i.e. bar) from the XML below using
simplexml_load_string? I'm stumped by the namespace called "ns" in the tag.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Body>
<ns:ExampleInterface_Output xmlns:ns="http://example.com/interfaces">
<ns:TagOne>Foo</ns:TagOne>
<ns:TagTwo>Bar</ns:TagTwo>
</ns:ExampleInterface_Output>
</SOAP-ENV:Body>
Thanks very much for your kind help!
Check this code:
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns:ExampleInterface_Output xmlns:ns="http://example.com/interfaces">
<ns:TagOne>Foo</ns:TagOne>
<ns:TagTwo>Bar</ns:TagTwo>
</ns:ExampleInterface_Output>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
$xse = new SimpleXMLElement($xml);
$exampleInterface = $xse
->children('SOAP-ENV', true)
->children('ns', true);
foreach ($exampleInterface->children('ns', true) as $key => $value) {
//Do your stuff
}
Well you can declare the "ns" namespace to simplexml_load_string like this:
$xml = simplexml_load_string($string, "SimpleXMLElement", 0, "ns", TRUE);
This says that "ns" is a namespace prefix (rather than a namespace URL). See the PHP doc page for simplexml_load_string for more details.
Another problem is that the Body element has a "SOAP-ENV" prefix which is not declared anywhere in the XML, so you will get a warning about this. However, the value of $xml will become an object structured like this:
SimpleXMLElement Object (
[ExampleInterface_Output] => SimpleXMLElement Object (
[TagOne] => Foo
[TagTwo] => Bar
)
)
But, warning aside, this might be exactly what you need. If the warning is a problem, you can simply remove the "SOAP-ENV" prefix from the start and end tags of the Body element.

Categories