XML Parsing in PHP (using simplexml_load_string) - php

I have the following code and I have been working to try to get this working.
<?php declare(strict_types=1);
$session_token = '?'; $xml = '';
$result = '<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://ws.careerbuilder.com/resumes/"><Packet><Errors /><SessionToken>3msk323msd-3312-CQ-2</SessionToken></Packet></string>
';
if ($result) {
$xml = simplexml_load_string($result);
print_r($xml);
if ($xml !== false) {
$session_token = $xml->SessionToken;
echo PHP_EOL.'Session: '. $session_token;
} else {
echo 'Error: XML does NOT appear to be valid';
}
} else
echo 'Error: result does NOT appear be valid';
The problem is no matter what I'm not able to extract the <SessionToken> value from the XML. When I use print_r() I get the following:
SimpleXMLElement Object
(
[0] => <Packet><Errors /><SessionToken>3msk323msd-3312-CQ-2</SessionToken></Packet>
)

Your input is entity-encoded. If this is really what it looks like, you'll need to decode it first:
$xml = simplexml_load_string(html_entity_decode($result));
$token = (string) $xml->Packet->SessionToken[0];

You document contains nested XML. The text content of the string element is serialized XML. So you need to parse it after reading it.
$result = '<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://ws.careerbuilder.com/resumes/"><Packet><Errors /><SessionToken>3msk323msd-3312-CQ-2</SessionToken></Packet></string>
';
$string = new SimpleXMLElement($result);
$packet = new SimpleXMLElement((string)$string);
var_dump($packet);
Output:
object(SimpleXMLElement)#2 (2) {
["Errors"]=>
object(SimpleXMLElement)#3 (0) {
}
["SessionToken"]=>
string(20) "3msk323msd-3312-CQ-2"
}

Related

Get elements from a XML content by PHP

I am trying to get elements from this XML content but returns empty:
<results>
<error>
<string>i</string>
<description>Make I uppercase</description>
<precontext></precontext>
<suggestions>
<option>I</option>
</suggestions>
<type>grammar</type>
</error>
</results>
And this is my code to extract element type of grammar :
$dom = new DOMDocument();
$dom->loadXml($output);
$params = $dom->getElementsByTagName('error'); // Find Sections
$k=0;
foreach ($params as $param) //go to each section 1 by 1
{
if($param->type == "grammar"){
echo $param->description;
}else{
echo "other type";
}
Problem is the script returns empty.
you can use simplexml_load_string()
$output = '<results>
<error>
<string>i</string>
<description>Make I uppercase</description>
<precontext></precontext>
<suggestions>
<option>I</option>
</suggestions>
<type>grammar</type>
</error>
</results>';
$xml = simplexml_load_string($output);
foreach($xml->error as $item)
{
//echo (string)$item->type;
if($item->type == "grammar"){
echo $item->description;
}else{
echo "other type";
}
}
You apparently haven't configured PHP to report errors because your code triggers:
Notice: Undefined property: DOMElement::$type
You need to grab <type> the same way you grab <error>, using DOM methods like e.g. getElementsByTagName(). Same for node value:
if ($param->getElementsByTagName('type')->length && $param->getElementsByTagName('type')[0]->nodeValue === 'grammar') {
// Feel free to add additional checks here:
echo $param->getElementsByTagName('description')[0]->nodeValue;
}else{
echo "other type";
}
Demo
I think is this what you want.
<?php
$output = '<results>
<error>
<string>i</string>
<description>Make I uppercase</description>
<precontext></precontext>
<suggestions>
<option>I</option>
</suggestions>
<type>grammar</type>
</error>
</results>';
$dom = new DOMDocument();
$dom->loadXml($output);
$params = $dom->getElementsByTagName('error'); // Find Sections
$k=0;
foreach ($params as $param) //go to each section 1 by 1
{
$string = $param->getElementsByTagName( "string" )->item(0)->nodeValue;
$description = $param->getElementsByTagName( "description" )->item(0)->nodeValue;
$option = $param->getElementsByTagName( "option" )->item(0)->nodeValue;
$type = $param->getElementsByTagName( "type" )->item(0)->nodeValue;
echo $type;
if($type == "grammar"){
echo $description ;
}else{
echo "other type";
}
}
?>
You're mixing DOM with SimpleXML. This is possible, but you would need to convert the DOM element node into a SimpleXML instance with simplexml_import_dom().
Or you use Xpath. getElementsByTagName() is a low level DOM method. Using Xpath expressions allows for more specific access with a lot less code.
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//error') as $error) {
var_dump(
[
'type' => $xpath->evaluate('string(type)', $error),
'description' => $xpath->evaluate('string(description)', $error)
]
);
}
Output:
array(2) {
["type"]=>
string(7) "grammar"
["description"]=>
string(16) "Make I uppercase"
}
Xpath expressions allow for conditions as well, for example you could fetch all grammar errors using //error[#type = "grammar"].

Generate XML out of Textfile using json_decode

I have this Textfile (namelist.txt):
{"0":"Mr Tony Test","1":"Ms Tina Testy"}
And I try to convert it into XML:
<?php
$xml = new DOMDocument();
$names = json_decode(file_get_contents('namelist.txt'));
foreach ($names as $name)
{
$xml_name = $xml->createElement($name);
}
$xml->save("rss.xml");
?>
I get the following Error:
Fatal error: Uncaught exception 'DOMException' with message 'Invalid
Character Error' in C:\xampp\htdocs\xibo\rss.php:6 Stack trace: #0
C:\xampp\htdocs\xibo\rss.php(6): DOMDocument->createElement('Mr Tony
Te...') #1 {main} thrown in C:\xampp\htdocs\xibo\rss.php on line 6
Is is even possible like this?
Edit 1:
Tried a solution by #spiky but I get a blank page as result:
<?php
$obj=('namelist.txt');
function json_to_xml($obj){
$str = "";
if(is_null($obj))
return "<null/>";
elseif(is_array($obj)) {
//a list is a hash with 'simple' incremental keys
$is_list = array_keys($obj) == array_keys(array_values($obj));
if(!$is_list) {
$str.= "<hash>";
foreach($obj as $k=>$v)
$str.="<item key=\"$k\">".json_to_xml($v)."</item>".CRLF;
$str .= "</hash>";
} else {
$str.= "<list>";
foreach($obj as $v)
$str.="<item>".json_to_xml($v)."</item>".CRLF;
$str .= "</list>";
}
return $str;
} elseif(is_string($obj)) {
return htmlspecialchars($obj) != $obj ? "<![CDATA[$obj]]>" : $obj;
} elseif(is_scalar($obj))
return $obj;
else
throw new Exception("Unsupported type $obj");
}
?>
If you decode the JSON is an object with two properties (0 and 1).
var_dump(json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}'));
Output:
object(stdClass)#1 (2) {
["0"]=>
string(12) "Mr Tony Test"
["1"]=>
string(13) "Ms Tina Testy"
}
You iterate the properties and use the values as element names. But they aren't valid names. Here is a static example producing the error:
$document = new DOMDocument();
$document->createElement('name with spaces');
Output:
Fatal error: Uncaught exception 'DOMException' with message
'Invalid Character Error' in /tmp/...
So you to make sure that you generate a valid XML. Likes this:
$json = json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}');
$document = new DOMDocument();
$names = $document->appendChild(
$document->createElement('names')
);
foreach ($json as $value) {
$names
->appendChild($document->createElement('name'))
->appendChild($document->createTextNode($value));
}
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<names>
<name>Mr Tony Test</name>
<name>Ms Tina Testy</name>
</names>
It is a better idea to use a definable node structure for the XML, not one that is defined by the data.
You named the result xml file 'rss.xml'. RSS is a defined format. So if you like to generate RSS you have to generate specific nodes.
$json = json_decode('{"0":"Mr Tony Test","1":"Ms Tina Testy"}');
$document = new DOMDocument();
$rss = $document->appendChild($document->createElement('rss'));
$rss->setAttribute('version', '2.0');
$channel = $rss->appendChild($document->createElement('channel'));
foreach ($json as $value) {
$item = $channel->appendChild($document->createElement('item'));
$item
->appendChild($document->createElement('title'))
->appendChild($document->createTextNode($value));
}
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<item>
<title>Mr Tony Test</title>
</item>
<item>
<title>Ms Tina Testy</title>
</item>
</channel>
</rss>

php simplexml not read <sheet r:id="rId1"/>

this is my code
$str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheet r:id="rId1"/></workbook>';
var_dump(simplexml_load_string($str));exit;
output:
object(SimpleXMLElement)#1 (1) { ["sheet"]=> object(SimpleXMLElement)#2 (0) { } }
rId1 doesn't show,why?
I would use Xpath to get that attribute.
<?php
$str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheet r:id="rId1"/></workbook>';
$xml = simplexml_load_string($str);
$id = $xml->xpath('sheet/#r:id');
echo 'r:id= ' . $id[0]
?>
Output:
r:id = rId1

Geting soap xsi:type from server response

I get response from SOAP server which has zero or more transactions of different types in each response.
Each transaction type is extension of base transaction type.
Different transaction types are processed differently.
Is there a way in PHP to get transaction type for each of transactions in response
(other then trying to figure difference in elements within each complex type)?
There is lot of types and lot of elements in each type....
Is there any class which could get this?
Following is just illustration...
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type1">
<id>24111</id><something>00000000</something><name>Blah</name>
</transactions>
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type8">
<id>24111</id><somethingelse>011</somethingelse>
</transactions>
I 'm not quite sure if this answer fits your question exactly. The following code snippet gets the type attribute value by their given namespaces and not the type of the namespaced value itself.
Done with PHP 's own Document Object Model.
<?php
$str = <<<XML
<content>
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type1">
<id>24111</id>
<something>00000000</something>
<name>Blah</name>
</transactions>
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type8">
<id>24111</id>
<somethingelse>011</somethingelse>
</transactions>
</content>
XML;
$doc = new DomDocument();
$doc->loadXML($str);
$nodeList = $doc->getElementsByTagName('transactions');
foreach ($nodeList as $element) {
$value = $element->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'type');
echo $value . "\n";
}
This will output the two given types "ns2:type1" and "ns2:type8".
I can parse your elements with simple_html_dom.
Here is the link for it.
An example is here :
<?php
include "simple_html_dom.php";
$html_nb = '
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type1"><id>24111</id><something>00000000</something><name>Blah</name>
</transactions>
<transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type8"><id>24111</id><somethingelse>011</somethingelse>
</transactions>';
function chtml($str){
if(strpos("<html>", $str) !== false)
return '<html><whole_code>'.$str.'</whole_code></html>';
else
return "<whole_code>".$str."</whole_code>";
}
function find_element_type($str){
if(preg_match_all("/\<(.*?)\>/i", $str, $matches))
return $matches[1][0];
else
return false;
}
function get_xsi_type($str){
if(preg_match_all("/xsi\:type\=\"(.*?)\"/i", $str, $matches))
return $matches[1][0];
else
return false;
}
$html = new simple_html_dom();
$html_2 = new simple_html_dom();
$html->load(chtml($html_nb));
$max_type = 10;
$element = $html->find('whole_code');
$e = $element[0]->innertext;
$html_2->load(chtml($e));
$k = 0;
while($html_2->find("whole_code",false)->children($k) != "")
{
$all = $html_2->find("whole_code",false)->children($k);
echo get_xsi_type($all) . "<br>";
echo find_element_type($all) . " : " .$all."<br>";
$k++;
}
echo "<hr>";
The result :
ns2:type1
transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type1" : 2411100000000Blah
ns2:type8
transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:type8" : 24111011

Simplexml get node by attribute

I've got xml file:
<?xml version="1.0" ?>
<xml>
<opis lang="en">My text</opis>
<opis lang="cz">My text2</opis>
</xml>
I want to get "My text2" - so a node where attribute lang is "cz":
$xml = simplexml_load_file($fileName);
$result = $xml->xpath('//xml/opis[#lang="cz"]')
but instead of value I get:
array(1) (
[0] => SimpleXMLElement object {
#attributes => array(1) (
[lang] => (string) cz
)
}
))
You could get the value like this:
$xml = simplexml_load_file($fileName);
$result = $xml->xpath('//xml/opis[#lang="cz"]');
foreach($result as $res) {
echo $res;
}
Try using DomDocument:
$xml = new DomDocument;
$xml->load('yourFile');
$xpath = new DomXpath($xml);
foreach ($xpath->query('//xml/opis[#lang="cz"]') as $rowNode) {
echo $rowNode->nodeValue; // will be 'this item'
}

Categories