I have this code:
$dom = new DOMDocument(); // new dom object
$dom->formatOutput = TRUE; //tidy the output
$root = $dom->appendChild($dom->createElement('PaymentNotificationResponse'));
$sxe = simplexml_import_dom( $dom );
$xml_pay = $sxe->addChild('Payments');
$paymnt = $xml_pay->addChild('Payment');
$paymnt->addChild('PaymentLogId','123');
$paymnt->addChild('Status', '0');
print_r($sxe);
This is supposed to print something like this:
<PaymentNotificationResponse>
<Payments>
<Payment>
<PaymentLogId>123</PaymentLogId>
<Status>0</Status>
</Payment>
</Payments>
</PaymentNotificationResponse>
But what i get is this:
SimpleXMLElement Object ( [Payments] => SimpleXMLElement Object ( [Payment] => SimpleXMLElement Object ( [PaymentLogId] => 123 [Status] => 0 ) ) )
Even when i use
print_r($sxe->asXML())
it just gives
1230
Simply doing:
echo $sxe->asXML();
Should do the trick.
Notice that unless you have the right headers, the browser might read it as HTML. You then have to inspect the source to see the actual XML.
To print the correct output you should print $sxe->asXML(), but if you want to have the output shown in the XML format on the browser you should also print the header in php:
header('Content-Type: application/xml; charset=utf-8')
for the sake of the example check the code bellow:
$dom = new DOMDocument(); // new dom object
$dom->formatOutput = TRUE; //tidy the output
$root = $dom->appendChild($dom->createElement('PaymentNotificationResponse'));
$sxe = simplexml_import_dom( $dom );
$xml_pay = $sxe->addChild('Payments');
$paymnt = $xml_pay->addChild('Payment');
$paymnt->addChild('PaymentLogId','123');
$paymnt->addChild('Status', '0');
print_r( header('Content-Type: application/xml; charset=utf-8') . $sxe->asXML());
Related
I am creating an XML file in PHP like this...
$myXML = new DOMDocument();
$myXML ->formatOutput = true;
$data = $myXML ->createElement('data');
$data->nodeValue = 'mydata';
$final->appendChild($data);
$myXML ->save('/mypath/myfile.xml');
This works, but how can I convert this to use saveXML() instead? I have tried like this but I get nothing
$myXML->saveXML();
Where am I going wrong?
I see two things:
$final is not declared. Change it.
In case saveXML() is called, the output has to be assigned to a variable or printed
Here goes the working code:
<?php
$myXML = new DOMDocument();
$myXML ->formatOutput = true;
$data = $myXML ->createElement('data');
$data->nodeValue = 'mydata';
$myXML->appendChild($data);
echo $myXML ->saveXML();
?>
Output:
<?xml version="1.0"?>
<data>mydata</data>
I have the following XML code which I want to read and get the value inside "content" tag.
"<?xml version='1.0' encoding='ISO-8859-1'?>
<ad modelVersion='0.9'>
<richmediaAd>
<content>
<![CDATA[<script src=\"mraid.js\"></script>
<div class=\"celtra-ad-v3\">
<img src=\"data: image/png, celtra\" style=\"display: none\"onerror=\"(function(img){ varparams={ 'channelId': '45f3f23c','clickUrl': 'http%3a%2f%2fexamplehost.com%3a53766%2fCloudMobRTBWeb%2fClickThroughHandler.ashx%3fadid%3de6983c95-9292-4e16-967d-149e2e77dece%26cid%3d352%26crid%3d850'};varreq=document.createElement('script');req.id=params.scriptId='celtra-script-'+(window.celtraScriptIndex=(window.celtraScriptIndex||0)+1);params.clientTimestamp=newDate/1000;req.src=(window.location.protocol=='https: '?'https': 'http')+': //ads.celtra.com/e7f5ce18/mraid-ad.js?';for(varkinparams){req.src+='&'+encodeURIComponent(k)+'='+encodeURIComponent(params[ k ]); }img.parentNode.insertBefore(req, img.nextSibling);})(this);\"/>
</div>]]>
</content>
<width>320</width>
<height>50</height>
</richmediaAd>
</ad>"
I tried 2 methods (SimpleXML and DOM). I managed to get the value but found the keyword "CDATA" missing. What I got inside "content" tag was:
<script src="mraid.js"></script>
<div class="celtra-ad-v3">
<img src="data: image/png, celtra" style="display: none"onerror="(function(img){ varparams={ 'channelId': '45f3f23c','clickUrl': 'http%3a%2f%2fexamplehost.com%3a53766%2fCloudMobRTBWeb%2fClickThroughHandler.ashx%3fadid%3de6983c95-9292-4e16-967d-149e2e77dece%26cid%3d352%26crid%3d850'};varreq=document.createElement('script');req.id=params.scriptId='celtra-script-'+(window.celtraScriptIndex=(window.celtraScriptIndex||0)+1);params.clientTimestamp=newDate/1000;req.src=(window.location.protocol=='https: '?'https': 'http')+': //ads.celtra.com/e7f5ce18/mraid-ad.js?';for(varkinparams){req.src+='&'+encodeURIComponent(k)+'='+encodeURIComponent(params[ k ]); }img.parentNode.insertBefore(req, img.nextSibling);})(this);"/>
</div>
I know the parser was trying to sort of "beautify" the XML by removing CDATA. But what I want is just the raw data with "CDATA" tag in it. Is there any way to achieve this?
Appreciate your help.
And below is my 2 methods for your reference:
Method 1:
$type = simplexml_load_string($response['adm']) or die("Error: Cannot create object");
$data = $type->richmediaAd[0]->content;
Yii::warning((string) $data);
Yii::warning(strpos($data, 'CDATA'));
Method 2:
$doc = new \DOMDocument();
$doc->loadXML($response['adm']);
$richmediaAds = ($doc->getElementsByTagName("richmediaAd"));
foreach($richmediaAds as $richmediaAd){
$contents = $richmediaAd->getElementsByTagName("content");
foreach($contents as $content){
Yii::warning($content->nodeValue);
}
}
I'll improve this if I can, but you can target explicitly the "CDATA Section" node of your content element and use $doc->saveXML( $node ) with the node as the parameter to get that exact XML element structure.
$doc = new \DOMDocument();
$doc->loadXML( $xml );
$xpath = new \DOMXPath( $doc );
$nodes = $xpath->query( '/ad/richmediaAd/content');
foreach( $nodes[0]->childNodes as $node )
{
if( $node->nodeType === XML_CDATA_SECTION_NODE )
{
echo $doc->saveXML( $node ); // string content
}
}
Edit: You may wish to support some redundancy if there is no CDATA found.
Without XPATH
$doc = new \DOMDocument();
$doc->loadXML( $xml );
$doc->normalize();
foreach( $doc->getElementsByTagName('content')->item(0)->childNodes as $node )
{
if( $node->nodeType === XML_CDATA_SECTION_NODE )
{
echo $doc->saveXML( $node ); // string content
}
}
Here are the codes:
$doc = new DomDocument('1.0');
// create root node
$root = $doc->createElement('root');
$root = $doc->appendChild($root);
$signed_values = array('a' => 'eee', 'b' => 'sd', 'c' => 'df');
// process one row at a time
foreach ($signed_values as $key => $val) {
// add node for each row
$occ = $doc->createElement('error');
$occ = $root->appendChild($occ);
// add a child node for each field
foreach ($signed_values as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
}
}
// get completed xml document
$xml_string = $doc->saveXML() ;
echo $xml_string;
If I print it in the browser I don't get nice XML structure like
<xml> \n tab <child> etc.
I just get
<xml><child>ee</child></xml>
And I want to be utf-8
How is this all possible to do?
You can try to do this:
...
// get completed xml document
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$xml_string = $doc->saveXML();
echo $xml_string;
You can make set these parameter right after you've created the DOMDocument as well:
$doc = new DomDocument('1.0');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
That's probably more concise. Output in both cases is (Demo):
<?xml version="1.0"?>
<root>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
</root>
I'm not aware how to change the indentation character(s) with DOMDocument. You could post-process the XML with a line-by-line regular-expression based replacing (e.g. with preg_replace):
$xml_string = preg_replace('/(?:^|\G) /um', "\t", $xml_string);
Alternatively, there is the tidy extension with tidy_repair_string which can pretty print XML data as well. It's possible to specify indentation levels with it, however tidy will never output tabs.
tidy_repair_string($xml_string, ['input-xml'=> 1, 'indent' => 1, 'wrap' => 0]);
With a SimpleXml object, you can simply
$domxml = new DOMDocument('1.0');
$domxml->preserveWhiteSpace = false;
$domxml->formatOutput = true;
/* #var $xml SimpleXMLElement */
$domxml->loadXML($xml->asXML());
$domxml->save($newfile);
$xml is your simplexml object
So then you simpleXml can be saved as a new file specified by $newfile
<?php
$xml = $argv[1];
$dom = new DOMDocument();
// Initial block (must before load xml string)
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// End initial block
$dom->loadXML($xml);
$out = $dom->saveXML();
print_R($out);
Tried all the answers but none worked. Maybe it's because I'm appending and removing childs before saving the XML.
After a lot of googling found this comment in the php documentation. I only had to reload the resulting XML to make it work.
$outXML = $xml->saveXML();
$xml = new DOMDocument();
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
$xml->loadXML($outXML);
$outXML = $xml->saveXML();
// ##### IN SUMMARY #####
$xmlFilepath = 'test.xml';
echoFormattedXML($xmlFilepath);
/*
* echo xml in source format
*/
function echoFormattedXML($xmlFilepath) {
header('Content-Type: text/xml'); // to show source, not execute the xml
echo formatXML($xmlFilepath); // format the xml to make it readable
} // echoFormattedXML
/*
* format xml so it can be easily read but will use more disk space
*/
function formatXML($xmlFilepath) {
$loadxml = simplexml_load_file($xmlFilepath);
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($loadxml->asXML());
$formatxml = new SimpleXMLElement($dom->saveXML());
//$formatxml->saveXML("testF.xml"); // save as file
return $formatxml->saveXML();
} // formatXML
Two different issues here:
Set the formatOutput and preserveWhiteSpace attributes to TRUE to generate formatted XML:
$doc->formatOutput = TRUE;
$doc->preserveWhiteSpace = TRUE;
Many web browsers (namely Internet Explorer and Firefox) format XML when they display it. Use either the View Source feature or a regular text editor to inspect the output.
See also xmlEncoding and encoding.
This is a slight variation of the above theme but I'm putting here in case others hit this and cannot make sense of it ...as I did.
When using saveXML(), preserveWhiteSpace in the target DOMdocument does not apply to imported nodes (as at PHP 5.6).
Consider the following code:
$dom = new DOMDocument(); //create a document
$dom->preserveWhiteSpace = false; //disable whitespace preservation
$dom->formatOutput = true; //pretty print output
$documentElement = $dom->createElement("Entry"); //create a node
$dom->appendChild ($documentElement); //append it
$message = new DOMDocument(); //create another document
$message->loadXML($messageXMLtext); //populate the new document from XML text
$node=$dom->importNode($message->documentElement,true); //import the new document content to a new node in the original document
$documentElement->appendChild($node); //append the new node to the document Element
$dom->saveXML($dom->documentElement); //print the original document
In this context, the $dom->saveXML(); statement will NOT pretty print the content imported from $message, but content originally in $dom will be pretty printed.
In order to achieve pretty printing for the entire $dom document, the line:
$message->preserveWhiteSpace = false;
must be included after the $message = new DOMDocument(); line - ie. the document/s from which the nodes are imported must also have preserveWhiteSpace = false.
based on the answer by #heavenevil
This function pretty prints using the browser
function prettyPrintXmlToBrowser(SimpleXMLElement $xml)
{
$domXml = new DOMDocument('1.0');
$domXml->preserveWhiteSpace = false;
$domXml->formatOutput = true;
$domXml->loadXML($xml->asXML());
$xmlString = $domXml->saveXML();
echo nl2br(str_replace(' ', ' ', htmlspecialchars($xmlString)));
}
I have an XML string that I have built up using the following example:
//add root
$Add = $dom->appendChild($dom->createElement('Add'));
//pCase
$pCase = $Add->appendChild($dom->createElement('pCase'));
//add elements
$LeadGenID = $pCase->appendChild($dom->createElement('LeadGenID'));
$LeadGenID->appendChild($dom->createTextNode('22'));
$Debtor = $pCase->appendChild($dom->createElement('Debtor'));
//address fields
$Addresses = $Debtor->appendChild($dom->createElement('Addresses'));
$Address = $Addresses->appendChild($dom->createElement('Address'));
//array of address objects should go here
$test1 = $dom->saveXML();
$sxe = simplexml_load_string($test1);
if ($sxe === false) {
echo 'Error while parsing the document';
exit;
}
$dom_sxe = dom_import_simplexml($sxe);
if (!$dom_sxe) {
echo 'Error while converting XML';
exit;
}
$dom = new DOMDocument('1.0', 'utf-8');
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);
echo $dom->save('application.xml');
This then outputs the following in my XML:
<Add>
<pCase>
<LeadGenID>22</LeadGenID>
<Debtor>
<Addresses><Address/></Addresses>
</Debtor>
</pCase>
I also need to output an array into this XML, so that the full output is as follows:
<Add>
<pCase>
<LeadGenID>22</LeadGenID>
<Debtor>
<Addresses>
<Address>
<Street>Some street</Street>
<Postcode>Some postcode</Postcode>
</Address>
</Addresses>
</Debtor>
</pCase>
I have tried to accomplish this using
$address_array = array (
$_POST['Street'] => 'Street',
$_POST['Postcode'] => 'Postcode'
);
$xml = new SimpleXMLElement('<Address/>');
array_walk_recursive($address_array, array ($xml, 'addChild'));
but at this point I am completely lost. The API I have been given is sparse on documentation to say the least but I'm getting closer with it, but I need to enter the address as an array for the gateway. I am new to PHP as I am primarily a frontend developer who has usually only done simple contact forms etc in PHP.
How can I output the XML example I've given above?
Thanks
Random weird stuff I've spot:
You start with new SimpleXMLElement('<Address/>') but your root node is <Addresses>
An $Address variable pops up from nowhere
A $dom object pops up from nowhere
You call createTextNode() which:
It isn't a SimpleXML method but a DOMDocument method
Expects a string as argument but it's fed with a SimpleXMLElement instance
Creates a text node
Have a look at http://www.lalit.org/lab/convert-php-array-to-xml-with-attributes/
It is a very small and simple to use library, if you just need array to xml.
My code builds an xml output from mysql dataset. Then I need to transform it to HTML. I saved it in a php variable and tried to use it in transformToXML( $XML ) as parameter but it raises it expects an object here. How do I convert this xml output to an object to be used as a parameter here. Here is my code:
<?php
// i am using the resultset to build an XML DOM but you can do whatever you like with it !
header("Content-type: text/xml");
$conn = new mysqli("localhost", "babar", "k4541616", "spec", 3306);
// one non-recursive db call to get the message tree !
$result = $conn->query("call message_hier(1)");
//--$result = $conn->query("call message_hier_all()");
$xml = new DomDocument;
$xpath = new DOMXpath($xml);
$msgs = $xml->createElement("messages");
$xml->appendChild($msgs);
// loop and build the DOM
while($row = $result->fetch_assoc()){
$msg = $xml->createElement("message");
foreach($row as $col => $val) $msg->setAttribute($col, $val);
if(is_null($row["parent_msg_id"])){
$msgs->appendChild($msg);
}
else{
$qry = sprintf("//*[#msg_id = '%d']", $row["parent_msg_id"]);
$parent = $xpath->query($qry)->item(0);
if(!is_null($parent)) $parent->appendChild($msg);
}
}
$result->close();
$conn->close();
$save = $xml->saveXML();//-> Here i save mxl in php var
//echo $save;
$xslt = new XSLTProcessor();
$XSL = new DOMDocument();
$XSL->load( 'msg.xsl');
$xslt->importStylesheet( $XSL );
header('Content-Type: application/xml');
print $xslt->transformToXML($save); //->error: expects an object here, string given.
?>
You will need to turn your XML string back into an object via DOMDocument::loadXML() before you can use it.