php simplexml_load_file - not able to see in print_r - php

I am new to simplexml parser in PHP. I have run the examples that I have found and they work as advertised. I can't get it to work with my program though. I have searched in here for hours.
I have an XML file called core.xml (note that the node tags have colons in):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dc:title>Lecture 3</dc:title>
<dc:creator>John Brown & Greg Smith</dc:creator>
<cp:lastModifiedBy>Greg Smith</cp:lastModifiedBy>
<cp:revision>165</cp:revision>
<dcterms:created xsi:type="dcterms:W3CDTF">2010-02-19T04:37:55Z</dcterms:created>
<dcterms:modified xsi:type="dcterms:W3CDTF">2014-01-30T02:41:30Z</dcterms:modified>
</cp:coreProperties>
I use following code to load it into the parser:
if (file_exists('core.xml')){
echo 'file exists <br>';
$xml_core = simplexml_load_file('core.xml');
print_r($xml_core);
}
else
{
exit('Failed to open core.xml.');
}
The file exists but all I get at the print_r is:
file exists
SimpleXMLElement Object ( )
How do I access the nodes? Other XML files that I have to use are many layers in depth.
Thanks

What you describe as an error pattern in your question is actually correct behaviour and not an error.
If you use print_r (or var_dump for that matter) on a SimpleXMLElement it will only show you some rudimentary information about that object and not the entire content of the XML document.
To see the whole XML, use the asXML() method instead. Alternatively to obtain debug information you can use a library that is specifically aware on how to debug SimpleXMLElement content's like simplexml_debug written by IMSop.
In your specific case, the object shows empty (no object members) because there aren't any nodes in the XML document within the default namespace (see: Namespaces in XML 1.0) that - after the more or less complex rules of SimpleXMLElement to array transitions were applied - would have been passed from the objects internal debug handler to the print_r or var_dump function to be displayed then. So only the class-name is given so that you can see it's an object of a certain class - and has no members:
SimpleXMLElement Object ( )
^ ^ ^
object type | `------ object fields (empty)
|
variable type
How to deal with that? It's very simple: Know the XML (you know it aleady) and obtain the data from it as it's documented:
PHP: Dealing with XML errors - Manual - Shows how you create (load) a SimpleXMLElement in a controlled manner and controlling error conditions.
PHP: Basic SimpleXML usage - Manual - Shows how to access data inside an XML document via the API of SimpleXMLElement.
As your XML element names contain colons, you should be made aware that these are so called XML namespaces. As you've seen differences in the print_r output, you will also see differences in accessing the child elements within that namespace. You have to use the children() method and specify the namespace of which you would like to obtain the child elements. If you use the xpath() method to access elements, you need to register an namespace prefix before you use it on the SimpleXMLElement you call that method on.
Some assorted selection of SimpleXML and XML Namespace related Q&A material here on site:
Parse XML with Namespace using SimpleXML (Feb 2009)
PHP namespace simplexml problems (Jan 2010)
PHP SimpleXML Namespace Problem (May 2011)
Parse XML namespaces with php SimpleXML (May 2013)
You can also obtain this information from the PHP manual, just take a look for namespace related information within the SimpleXMLElement API documentation.

You can use file_get_contents to load XML file.
Try
if(file_exists('core.xml'))
{
echo 'file exists <br>';
$xml_core = file_get_contents('core.xml');
$xml = new SimpleXMLElement($xml_core);
print_r($xml);
}
else
{
exit('Failed to open core.xml.');
}

Related

Access Property of nested namespace in XML document

I need to access the value of an attribute located within a nested namespace in a XML document. Here is a sample of the XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp:epp xmlns:epp="urn:ietf:params:xml:ns:epp-1.0">
<epp:response>
<epp:result code="1000">
<epp:msg>Domain Check Command completed successfully</epp:msg>
</epp:result>
<epp:msgQ count="4" id="OTE-EPP-155DF5E824E-1BC86"/>
<epp:resData>
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:cd>
<domain:name avail="1">example.com</domain:name>
</domain:cd>
</domain:chkData>
</epp:resData>
<epp:trID>
<epp:clTRID>123</epp:clTRID>
<epp:svTRID>456</epp:svTRID>
</epp:trID>
</epp:response>
</epp:epp>
In the above, I need to access the "avail" attribute which from what I can gather is located in a nested namespace domain within the epp namespace.
I am using simplexml_load_string($xml) to access the properties. I am able to access the epp namespace but my lack of XML knowledge is failing me on this one :)
Thank you in advance!
EDIT
As the question is marked as a duplicate I want to clear up that I am looking for a value of a property located within a nested namespace.
I have tried to access the property via xpath but have only received undefined namespace prefix errors:
echo $data->xpath('/domain:name')->attributes()->avail;
echo $data->xpath('/epp:response/epp:resData/domain:chkData/domain:cd/domain:name')->attributes()->avail;
I have also tried the above without the epp namespace but the same result. I know how to get the value from a single namespace but not from a nested namespace.
Another Edit:
I am still struggling. I really cannot get xpath to find the associated namespace element within the xml document. The below code is what I'm trying.
I have tried to also just do a vardump on $sxe->xpath('//d:name')) but get an empty array, indicating no values?
Please can someone help a brother out :)
$sxe = simplexml_load_string($result, "SimpleXMLElement", 0, "epp", true);
$code = $sxe->response->result->attributes()->code;
if ($code == 1000) {
$sxe->registerXPathNamespace('d','ietf:params:xml:ns:domain-1.0');
echo $sxe->xpath('//d:name')->attributes()->avail;
}
exit;
YET ANOTHER EDIT
Following another answer I changed my simplexml_load_string() function declaration and attempted to declare 2 xpath namespaces (feels like the closest I have gotten so far) - I am able to get the value in the epp namespace but still no luck with the domain namespace.
$sxe = simplexml_load_string($result,NULL,NULL,'urn:ietf:params:xml:ns:epp-1.0');
$sxe->registerXPathNamespace('epp', 'ietf:params:xml:ns:epp-1.0');
$sxe->registerXPathNamespace('domain', 'ietf:params:xml:ns:domain-1.0');
$code = $sxe->xpath('//epp:result')[0]->attributes()->code;
if ($code == 1000) {
print_r($sxe->xpath('domain:name'));
print_r($sxe->xpath('//domain:name'));
}
exit;

Deserializing or parse XML response in Symfony2

I am calling a API method through cURL and I got this response:
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>75080000002s5siAAA</id>
<operation>query</operation>
<object>User</object>
<createdById>00580000008ReolAAC</createdById>
<createdDate>2015-06-23T13:03:01.000Z</createdDate>
<systemModstamp>2015-06-23T13:03:01.000Z</systemModstamp>
<state>Open</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>0</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>0</numberBatchesTotal>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>34.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
I want to access|parse that result in a easy way and I don't know if I should deserializing the XML or just try to read it using some PHP native XML function. So ideas on this first doubt?
If it is better to deserialize the XML then I have read this post "Deserializing XML with JMSSerializerBundle in Symfony2" and is not clear at all for me if I will need an entity to achieve that. Also this other topic
and still confuse to me. Any advice on that? Experiences? Suggestions?
It depends on your intention. If you want to directly push part or all of the XML to an entity/document object for saving to a database then the JMSSerializerBundle can do this very smartly and is definitely the best way to do it.
If however you just want to extract one or two fields from the xml and use them in other business logic then simply loading the xml into a SimpleXML object is often simpler.
You can use any object (not only an entity) to deserialize the XML file to. It is recommended to deserialize to a object because you probably want to use it in an OOP way.
This is a well explained blog about JMS serializer (bundle) including a XML deserialization example in a user object: http://johnkary.net/blog/deserializing-xml-with-jms-serializer-bundle/

How do I call SOAP methods in PHP using namespaces (in params and methods) and nested structures (in params)?

Assume I have this XML (it is a SOAP call)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ext="http://api.movilway.net/schema/extended">
<soapenv:Header/>
<soapenv:Body>
<ext:GetBalanceRequest>
<ext:AuthenticationData>
<ext:Username>Foo</ext:Username>
<ext:Password>Bar$123!password</ext:Password>
<ext:SessionID>as3hy4ri37g2f345</ext:SessionID>
</ext:AuthenticationData>
<ext:DeviceType>3</ext:DeviceType>
</ext:GetBalanceRequest>
</soapenv:Body>
</soapenv:Envelope>
(Foo, Bar$123!password, as3hy4ri37g2f345 and 3 are just sample values)
Usually, when I want to do simple SOAP calls, I use a SoapClient like this:
$sc = new SoapClient('http://my.url/my/service?wsdl');
$result = $sc->someMethod(array('some' => 'params'));
But this one seems to use xsd namespaces and nested structures.
Q: How do I call methods with namespaces prefixes (ext:, in this case) AND parameters with namespaces prefixes (and nested structures)?
Edit: What I tried involves including the namespace as the uri option. And got an exception like this:
SoapFault : Function ("GetBalanceRequest") is not a valid method for this service
The code I tried was this:
try {
$client = new SoapClient('http://THEURLHERE/Path/To/The/Service?wsdl', array('uri' => 'http://api.movilway.net/schema/extended'));
print_r($client->GetBalanceRequest(
array(
'AuthenticationData' => array(
'Username' => 'MYUSERHERE',
'Password' => 'MYPASSWORDHERE'
),
'DeviceType' => 1
)
));
} catch(Exception $e) {
print_r($e);
}
Assume there's no error nor typo since I got the required XML directly from the documentation.
Q+: What must I add to the code to send such request?
Firstly, the correct term is not "extension", but "namespace" - it's just coincidence that the namespace here is called "extended" and has been given the alias ext: in the example.
Secondly, an XML namespace is simply a way of saying "these elements and attributes are of a particular type"; it does not automatically imply any special structure beyond normal XML - it has no automatic relationship to an XSD, for instance. A namespace is uniquely identified by a URI, which needn't actually point anywhere (see this previous answer for more on that). Within a document, it is given an arbitrary prefix, so that you don't have to write the URI next to every element.
SOAP itself uses the namespace http://schemas.xmlsoap.org/soap/envelope/ for the elements that represent the SOAP "envelope", here given the alias soapenv. The "body" of the SOAP message is not in that namespace, so it is common for SOAP services to declare their elements as part of some other specific namespace; if they didn't, they would be in the default, nameless, namespace.
So, so much for theory. On to practice:
If you are using a WSDL to load the web service, and that WSDL is properly formed, the SOAPClient class should add the appropriate namespace to your request automatically. Since the request exists entirely inside that namespace, there is no need to distinguish between "AuthenticationData in namespace http://api.movilway.net/schema/extended" and just "AuthenticationData".
If this doesn't work for some reason, or you have no WSDL, you may need to create SoapVar objects with the appropriate namespace assigned to them.
However, based on the error message you just edited into your question, all of the above may be completely irrelevant, because the problem might have nothing to do with namespaces at all - you are operating in WSDL mode, and the client is telling you that the method doesn't exist. So, the obvious question to me is, is that method definitely defined in that WSDL file?

Attribute not creating using DomDocument in PHP

I am stuck with DomDocument
This thing is working fine, no doubt -
$resource1->appendChild($dom->createAttribute('type'))
->appendChild($dom->createTextnode("webcontent"));
It is adding type="webcontent" to resource node
However when I am using this code its not adding it to it -
$resource1->appendChild($dom->createAttribute('adlcp:scormType'))
->appendChild($dom->createTextnode("sco"));
Expected to generate - adlcp:scormType="sco" <-- Not Working
However If I am creating
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <-- Working
Code -
$manifestNode->appendChild($dom->createAttribute('xmlns:xsi'))
->appendChild($dom->createTextNode("http://www.w3.org/2001/XMLSchema-instance"));
Let me know what I am doing wrong and how do I make it working
EDIT
Error -
XML Parsing Error: prefix not bound to a namespace
Googled same with the keyword - xml parsing error prefix not bound to a namespace php but not much help.
To set an attribute on a node:
$resource1->setAttribute('type', 'webcontent');
To set a namespaced attribute on a node (assuming this is the namespace represented by the "adlcp" prefix):
$resource1->setAttributeNS('http://www.adlnet.org/xsd/adlcp_rootv1p2', 'adlcp:scormType', 'sco');

Cakephp and PHP: How to change xml value in xml?

I want to update to_status value.
I have following xml file.
<challenges>
<challenge>
<challenge_id>1385</challenge_id>
<debate_id>988</debate_id>
<comment_id>157</comment_id>
<from_id>42</from_id>
<to_id>3</to_id>
<from_status> true</from_status>
<to_status> false</to_status>
<timestamp>1320933898</timestamp>
</challenge>
</challenges>
How can i update it?
Look into CakePHP's "XML" class. In versions prior to 2.0, you have to "App::import('Xml')" the XML class but in 2.0 it is a core library.
With the XML class, you can render the XML as an array, manipulate it the way you want, and simply re-transform it into an XML string.
Check out these links:
CakePHP 1.3 XML : http://book.cakephp.org/view/1473/XML
CakePHP 2.0 XML : http://book.cakephp.org/2.0/en/core-utility-libraries/xml.html?highlight=xml

Categories