How to use/convert xml string as parameter in xsl transformation - php

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.

Related

Add Node to the XML Before Saving

how to add xml node <TypeId>HDU5K3KDI23F</TypeId> to the 'Top' node of the XML variable before saving.
XML data i am getting is coming from API as a Response.
When i use the below code,xml response data does get saved, but the 'Typeid' Node is not getting saved in that file.
XML Response Data looks like this
<GetCategories>
<GetProduct>
<Data>
<Id>87772873</Id>
<Name>Foods and Beverages</Name>
<Top>
<CategoryId>028392323</CategoryId>
<CategoryName>Categories</CategoryName>
</Top>
</Data>
</GetProduct>
</GetCategories>
Code
$dom = new DOMDocument;
$dom->loadXML($response->toXML());
$dom->preserveWhiteSpace = FALSE;
$Xpath = new DOMXpath($dom);
foreach ($Xpath->evaluate('/GetCategories/GetProduct/Data/Top[1]') as $data)
{
$type = $data->appendChild($dom->createElement('TypeId'));
$type->appendChild($dom->createTextNode('HDU5K3KDI23F'));
}
$dom->formatOutput = TRUE;
$xmldata = $dom->saveXML();
echo $xmldata;
$myfile = file_put_contents('data.xml', $xmldata.PHP_EOL , FILE_APPEND | LOCK_EX);
Change the code in foreach as follows:
First create element with value and append to your data.
foreach ($Xpath->evaluate('/GetCategories/GetProduct/Data/Top[1]') as $data)
{
$type = $dom->createElement('TypeId', 'HDU5K3KDI23F');
$data->appendChild($type);
}

domDocument's formatOutput property writes inline [duplicate]

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)));
}

Print XML node using XPath in PHP

I'm trying to print complex XML's node values using XPath, I have attached an image for helping to see the path which I need to reach (red underline).
Original XML file can be found here
I was trying something like that:
<?php
$xml = simplexml_load_file('document.xml');
echo "<strong>Using direct method...</strong><br />";
$names = $xml->xpath('/w:document/w:body/w:tbl[0]/w:tr[1]/w:tc[0]/w:p/w:r/w:t');
foreach($names as $name) {
echo "Found $name<br />";
}
?>
This method I am using to replace this node:
$file = "document.xml";
$fp = fopen($file, "rb") or die("error");
$str = fread($fp, filesize($file));
$xml = new DOMDocument();
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");
$root = $xml->documentElement;
$fnode = $root->childNodes->item(0);
$ori = $fnode->childNodes->item(1);
$ori1 = $ori->childNodes->item(3);
$ori2 = $ori1->childNodes->item(1);
$ori3 = $ori2->childNodes->item(1);
$ori4 = $ori3->childNodes->item(1);
$ori5 = $ori4->childNodes->item(1);
$wt = $xml->createElement("w:t");
$wtText = $xml->createTextNode("".$name." ".$item."");
$wt->appendChild($wtText);
$ori4->replaceChild($wt,$ori5);
$xml->save("document.xml");
<?php
// Load XML
$doc = new DOMDocument();
$doc->load("document.xml");
// Use xpath to grab the node in question. I copied your xpath
// query as-is, assuming it was capable of targetting exactly
// the node you are trying to replace. If it returns more than
// one node, then only the first will be replaced.
// If this isn't what you want, I suggest modifying your xpath
// query to match exactly the single node you want to replace.
$xpath = new DOMXPath($doc);
$oldElement = $xpath->query("/w:document/w:body/w:tbl[0]/w:tr[1]/w:tc[0]/w:p/w:r/w:t")->item(0);
$newElement = $doc->createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:t", $name . " " . $item);
// Replace old element with new element
$oldElement->parentNode->replaceChild($newElement, $oldElement);
?>

How to load a xml file in php so that i can use xpath on it?

I have a problem with php,
If I implement this code below then nothing will be happen.
$filename = "/opt/olat/olatdata/bcroot/course/85235053647606/runstructure.xml";
if (file_exists($filename)) {
$xml = simplexml_load_file($filename, 'SimpleXMLElement', LIBXML_NOCDATA);
// $xpath = new DOMXPath($filename);
}
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
$res = $xpath->query('/org.olat.course.Structure/rootNode/children/org.olat.course.nodes.STCourseNode/shortTitle');
foreach ($res as $entry) {
echo "{$entry->nodeValue}<br/>";
}
If I change the contents of $xml in the content with the content of the $filename
$xml = '<org.olat.course.Structure><rootNode class="org.olat.course.nodes.STCourseNode"> ... ';
then it works, so i think that there is something wrong with loading methode of the xml file,
I've also tried to load the xml file as a Domdocument but it won't work neither.
And in both cases, it does work if I collect xml data via xml
for example this works
echo $Course_name = $xml->rootNode->longTitle;
loadXML takes a string as input, not the return value of simplexml_load_file. Just use file_get_contents to get the (full) contents of a file as string

parsing a DOMNodeList in PHP

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)...

Categories