I have some simple XML parser
$doc = new DOMDocument();
$doc->load("xml/UploadTask.xml");
$items = $doc->getElementsByTagName( "item" );
foreach( $items as $item )
{
$keys = $item->getElementsByTagName( "key" );
$key = $keys->item(0)->nodeValue;
$values = $item->getElementsByTagName( "value" );
$value = $values->item(0)->nodeValue;
echo "$key - $value";
}
and it work perfectly for me, how ever if i need to parse XML which comes via POST, my code to load XML looks like (I put it on top of file):
$xml = file_get_contents('php://input');
echo $xml;
and this return XML which comes, everything works right , how ever if I load $xml to DOM (basicly replace 2. line on $doc->load($xml);I'm getting no output, no echo of values.
while I try to debug this I notice that if I use file var_dump($items)
i get answer:
object(DOMNodeList)#2 (1) {
["length"]=>
int(0)
}
if I do same var_dump() with file loaded i get answer:
object(DOMNodeList)#2 (1) {
["length"]=>
int(2)
}
where int(2) represent number of matches for this criteria found.
So my question is are there some limits for parsing XML loading with file_get_contents ?
and also, is there any workaround on this?
Thanks guys.
DOMDocument::load() loads a file (or an URL using the Streamwrappers), not a string. DOMDocument::loadXml() loads a string.
$xml = '<foo>Hello World</foo>';
$document = new DOMDocument();
$document->loadXml($xml);
var_dump($document->documentElement->textContent);
Output:
string(11) "Hello World"
Related
Hey everybody thanks for your time, I'm trying to parse a big XML file (pic bellow) and to get the text of specific nodes using XPATH expression in PHP.
Here is my php :
<?php
echo "[Generation Starts !]\n";
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (file_exists('../source/particuliers/arborescence.xml')) {
$xml = new SimpleXMLElement(file_get_contents('../source/particuliers/arborescence.xml'));
$xml->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
$themes = $xml->xpath("/Arborescence/Item[#type='Theme']/Titre/text()");
var_dump($themes);
$JSON = json_encode($themes, JSON_UNESCAPED_UNICODE);
file_put_contents('testing.json', $JSON);
echo "[Generation Done !]\n";
} else {
echo "File wasn't found\n";
}
I won't put the whole XML file here as it is way too big but here is a pic so you see the structure
Using this XPATH expression /Arborescence/Item[#type='Theme']/Titre/text() I expected to get text from my nodes but I only have an empty array with the right number of elements in it but all empty.
Anything I'm doing wrong ?
The result of SimpleXMLElement::xpath() is always an array of SimpleXMLElement objects (or false for an invalid expression). SimpleXMLElement object represent element nodes, but the extension does some magic for text nodes and attributes.
Stripping down the code from the question into an example:
$xml = <<<'XML'
<Arborescence>
<Item type="Theme">
<Titre>Loisirs</Titre>
</Item>
</Arborescence>
XML;
$xml = new SimpleXMLElement($xml);
$themes = $xml->xpath("/Arborescence/Item[#type='Theme']/Titre/text()");
var_dump($themes);
Output:
array(1) {
[0]=>
object(SimpleXMLElement)#2 (1) {
[0]=>
string(7) "Loisirs"
}
}
The result is an array with a single SimpleXMLElement that contains the text. You can use array_map() to cast all returned objects to strings.
$xml = new SimpleXMLElement($xml);
$themes = array_map(
function(SimpleXMLElement $element) {
return (string)$element;
},
$xml->xpath("/Arborescence/Item[#type='Theme']/Titre/text()")
);
Output:
array(1) {
[0]=>
string(7) "Loisirs"
}
I am trying to use simplexml_load_file() to load an XML file and reach <dc:title> tags, but when I dump the $xml variable that loaded my xml file all the tags that starts with <dc: doesn't show. Is there a way of telling the parser to include them? should I use a different parser?
Here's my example file's code:
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" prefix="ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/" unique-identifier="pub-id" version="3.0" xml:lang="en">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title>test</dc:title>
</metadata>
</package>
Code I used to check for which tags are seen:
$xml = simplexml_load_file('test.xml');
echo '<pre>';var_dump($xml);echo '</pre>';
And the result:
object(SimpleXMLElement)#1 (2) {
["#attributes"]=>
array(3) {
["prefix"]=>
string(80) "ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/"
["unique-identifier"]=>
string(6) "pub-id"
["version"]=>
string(3) "3.0"
}
["metadata"]=>
object(SimpleXMLElement)#2 (0) {
}
}
metadata is in fact, empty. Thoughts?
First, dc is a namespace, not part of tag name. For testing purpose you can print the namespaces used in the given xml. Executing the snippet
$namespaces = $xml->getNamespaces(true);
var_dump($namespaces);
will output
array(3) {
'' =>
string(28) "http://www.idpf.org/2007/opf"
'xml' =>
string(36) "http://www.w3.org/XML/1998/namespace"
'dc' =>
string(32) "http://purl.org/dc/elements/1.1/"
}
You have to register a prefix for the namespace for usage with xpath, then you can use it for selection:
$xml->registerXPathNamespace('b', 'http://purl.org/dc/elements/1.1/');
$a =$xml->xpath('//b:*/text()');
foreach($a as $t) {
print($t."\n");
}
This will output test of the element you want to get.
You can use
$xml = simplexml_load_file('test.xml');
$result = $xml->metadata->children('dc', true);
result of the code above is an object, now convert to array
$array = json_decode(json_encode($result),TRUE);
Result of $array
array(1) {
["title"]=>string(4) "test"
}
In a response we receive an xml file, then convert to SimpleXMLElement, then access the elements and attributes as needed. However, we are getting "Trying to get property of non-object" when xml is loaded directly from string response vs from saved response.
//This code works
$response = simplexml_load_file( "response.xml" );
var_dump($response);
echo $response->RESPONSE->RESPONSE_DATA->FILE_INFORMATION['Order_Number'];
//Returns
//object(SimpleXMLElement)#153 (4) { ["#attributes"]=> array(1)...the rest of the xml file...
//Order_Number
//This code returns error
$response = simplexml_load_string( $response );
var_dump($response);
echo $response->RESPONSE->RESPONSE_DATA->FILE_INFORMATION['Order_Number'];
//Returns
//object(SimpleXMLElement)#153 (1) { [0]=> string(33864) "" }
//Notice: Trying to get property of non-object in...
What would cause the xml to fail when using simplexml_load_string instead of simplexml_load_file?
Here is a snippet of the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<RESPONSE_GROUP>
<RESPONSE>
<RESPONSE_DATA>
<FILE_INFORMATION Order_Number="19222835">
...
</FILE_INFORMATION>
</RESPONSE_DATA>
</RESPONSE>
</RESPONSE_GROUP>
You've just overlooked a little detail here. It is correct what you say for the first part:
$response = simplexml_load_file( "response.xml" );
This loads the XML document from the file. However when you look at the second part:
$response = simplexml_load_string( $response );
You don't load from string response. $response represents the SimpleXMLElement you've just created from file. The more "correct" example is:
$buffer = file_get_contents( "response.xml" );
$response = simplexml_load_string( $buffer );
You perhaps just were confused due to variable-reuse (taken the same named variable for two different things).
And better as var_dump is to check with $response->asXML() as it will show you the document as XML which shows better what you have (or not).
This works for me:
<?php
$response = '<?xml version="1.0" encoding="UTF-8"?>
<RESPONSE_GROUP>
<RESPONSE>
<RESPONSE_DATA>
<FILE_INFORMATION Order_Number="19222835">
...
</FILE_INFORMATION>
</RESPONSE_DATA>
</RESPONSE>
</RESPONSE_GROUP>';
//This code returns error
$response = simplexml_load_string( $response );
var_dump($response);
echo $response->RESPONSE->RESPONSE_DATA->FILE_INFORMATION['Order_Number'];
?>
Output:
object(SimpleXMLElement)#1 (1) {
["RESPONSE"]=>
object(SimpleXMLElement)#2 (1) {
["RESPONSE_DATA"]=>
object(SimpleXMLElement)#3 (1) {
["FILE_INFORMATION"]=>
string(33) "
...
"
}
}
}
19222835
I have the following response from a XML api , I want to display the text that is placed in the comments section .
<OTA_AirDetailsRS PrimaryLangID="eng" Version="1.0" TransactionIdentifier=""><Errors><Error Type="ERR" FLSErrorCode="-10" FLSErrorName="Invalid Input"/></Errors><!-- Reason for error: The Date parameter is not valid [2014-05-16] --></OTA_AirDetailsRS>
I have used this :
...
$query = curl_exec($curl_handle);
curl_close($curl_handle);
$xml = new SimpleXmlElement($query);
if($xml->Errors){
$doc = new DOMDocument;
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
foreach ($xpath->query('//comment()') as $comment)
{
var_dump($comment->textContent);
}
Its not displaying anything in this case , but if instead of passing xml response , I pass it a simple xml in string format , it is working . Please suggest if something is wrong.
You need to load the XML, not the object from your SimpleXmlElement call:
$doc = new DOMDocument;
$doc->loadXML($query);
Then your script outputs:
string(64) " Reason for error: The Date parameter is not valid [2014-05-16] "
A web service return Xml of format
<string>
<NewDataSet>
<DealBlotter>
<CustomerReference>161403239</CustomerReference>
<Symbol>EUR/USD</Symbol>
<BuySell>S</BuySell>
<ContractValue>-100000</ContractValue>
<Price>1.35070</Price>
<CounterValue>-135070</CounterValue>
<TradeDate>2011-01-20 22:05:21.690</TradeDate>
<ConfirmationNumber>78967117</ConfirmationNumber>
<Status>C</Status>
<lTID>111913820</lTID>
</DealBlotter>
</NewDataSet>
</string>
Now i am using curl to access this and then -
$xml = simplexml_load_string($result);
$dom = new DOMDOcument();
// Load your XML as a string
$dom->loadXML($xml);
// Create new XPath object
$xpath = new DOMXpath($dom);
$res = $xpath->query("/NewDataSet/DealBlotter");
foreach($res as $node)
{
print "i went inside foreach";
$custref = ($node->getElementsByTagName("CustomerReference")->item(0)->nodeValue);
print $custref;
$ccy = ($node->getElementsByTagName("Symbol")->item(0)->nodeValue);
print $ccy;
$type = ($node->getElementsByTagName("BuySell")->item(0)->nodeValue);
$lots = ($node->getElementsByTagName("ContractValue")->item(0)->nodeValue);
$price = ($node->getElementsByTagName("Price")->item(0)->nodeValue);
$confnumber = ($node->getElementsByTagName("ConfirmationNumber")->item(0)->nodeValue);
$status = ($node->getElementsByTagName("Status")->item(0)->nodeValue);
$ltid = ($node->getElementsByTagName("lTID")->item(0)->nodeValue);
$time = ($node->getElementsByTagName("TradeDate")->item(0)->nodeValue);
}
But nothing is getting printed. except the dummy statement.
using $res = $xpath->query("/string/NewDataSet/DealBlotter"); did not help. Also a print_r($res); gives output as DOMNodeList obect.
Doing this also does not print anything
$objDOM = new DOMDocument();
$objDOM->load($result);
$note = $objDOM->getElementsByTagName("DealBlotter");
foreach( $note as $value )
{
print "hello";
$tasks = $value->getElementsByTagName("Symbol");
$task = (string)$tasks->item(0)->nodeValue;
$details = $value->getElementsByTagName("Status");
$detail = (string)$details->item(0)->nodeValue;
print "$task :: $detail <br>";
}
There are a few problems.
With how you're loading the xml. Get rid of the simplexml line. It's not needed, and is messing things up. Instead just do $dom->loadXml($result);. There's no reason to load SimpleXML first if you're going to pass it directly into DomDocument.
With your query, the / operator is the direct decendent operator. So it means directly next to. So your first tag should be the root. So either add the root onto it:
$res = $xpath->query("/string/NewDataSet/DealBlotter");
Or make the leading slash into // which selects any matching decendent:
$res = $xpath->query("//NewDataSet/DealBlotter");
And finally, doing a var_dump on $res isn't going to tell you much. Instead, I like to do var_dump($res->length) since it'll tell you how many matches it has rather than that it's a domnodelist (which you already know)...