Print XML node using XPath in PHP - 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);
?>

Related

write a variable into an xml file using php

Hey there i'm trying to generate an XML file with php variables.
but echo or print don't seem to work watch my snippet below.
How could i achieve what i'm trying todo?
$xml = new DOMDocument();
$root = $xml->createElement('package');
$root = $xml->appendChild($root);
$title = $xml->createElement('id' , echo $_GET['bundleid']);
$title = $root->appendChild($title);
As luenib pointed out, you generally don't put "echo" before variables that you pass to functions as arguments. Below is a simple example of outputting XML to browser or writing to file.
$xml = new DOMDocument();
$root = $xml->createElement('package');
$root = $xml->appendChild($root);
$title = $xml->createElement('id' , $_GET['bundleid']); // no "echo" before variable
//$title = $xml->createElement('id' , $_POST['bundleid']);
//$title = $xml->createElement('id' , $bundleid);
//$title = $xml->createElement('id' , 'bundleid');
$title = $root->appendChild($title);
$xml->formatOutput = true;
$xml_string = $xml->saveXML();
// Store XML to file.
file_put_contents('path/myXmlFile.xml',$xml_string);
// Output XML to browser.
//header("Content-type: text/xml");
//echo $xml_string;

php - XML DomElement won't prettify

Im trying to create a XML file using php.
When I print my xml it prints it all in one line and not in proper format.
$xml = new DomDocument();
**$xml->preserveWhiteSpace = false;
$xml->FormatOutput = true;**
$parent = $xml->createElement("foo");
$parent->setAttribute("xmlns", "http://");
$parent->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
$parent->setAttribute("xsi:schemaLocation", "link");
$xml->appendChild($parent);
$child = $xml->createElement("foo1");
$parent->appendChild($child);
$subchile = $xml->createElement($foo);
$child->appendChild($subchile);
$s_c = $xml->createElement("foo3",$foo3);
$subchile->appendChild($s_c);
echo "<xmp>" . $xml->saveXML() . "<xml>";
$xml->save($file_name)
it prints everything without indentations etc.
I read other questions here and followed the answers but still nothing. Can you help?
changed $xml->FormatOutput = true; ---> $xml->formatOutput = true;

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

Can't add CDATA into my XML string using simplexml with php

I'm simply wanting to add cdata to an xml node - description. My xml function is below. I have tried using bits of the following function on php.net in my function
<?php
function updateXMLFile($itemName, $description, $pageName, $imageFileName)
{
$imageSrc = "<img src='http://nicolaelvin.com/authoring/phpThumb/phpThumb.php?src=../images/" . $imageFileName . "&w=100'/>";
$id = strtolower($id = str_replace(' ', '_', $itemName));
$directLinkToItem = 'http://nicolaelvin.com/authoring/' . $pageName . '.php#' . $id;
$xml = simplexml_load_file('nicolaElvinsPortfolio.xml');
$item = $xml->channel->addChild('item');
$item->addChild('title', $itemName);
$item->addChild('pubDate', date('r'));
$item->addChild('link', $directLinkToItem);
$item->addChild('description');
$cdata->description->createCDATASection('testyfhgjhsgsdjahgs');
$item->appendChild($cdata);
///Format XML to save indented tree rather than one line
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
//Save XML to file - remove this and following line if save not desired
$dom->save('nicolaElvinsPortfolio.xml');
}
//function from php.net
function sxml_cdata($path, $string)
{
$dom = dom_import_simplexml($path);
$cdata = $dom->ownerDocument->createCDATASection($string);
$dom->appendChild($cdata);
}
?>
Try this on for size. Let me know if you have any problems with it/questions about it (FIXED).
function updateXMLFile($itemName, $description, $pageName, $imageFileName) {
// Path to file that will be used
$filePath = 'nicolaElvinsPortfolio.xml';
// Create links - don't forget to escape values appropriately with urlencode(), htmlspecialchars() etc
$imageSrc = "<img src='".htmlspecialchars('http://nicolaelvin.com/authoring/phpThumb/phpThumb.php?src=../images/'.urlencode($imageFileName).'&w=100')."'/>";
$directLinkToItem = 'http://nicolaelvin.com/authoring/'.urlencode($pageName).'.php#'.urlencode(strtolower(str_replace(' ', '_', $itemName)));
// Create the CDATA value - whatever you want this to look like
$cdata = "$description: $imageSrc";
// Create a DOMDocument
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// Load data from file into DOMDocument
if (!$dom->load($filePath)) throw new Exception("Unable to load data source file '$filePath'");
// Create the new <item> and add it to the document
$item = $dom->getElementsByTagName('channel')->item(0)->appendChild(new DOMElement('item'));
// Add the <item>'s sub elements
$item->appendChild(new DOMElement('title', $itemName));
$item->appendChild(new DOMElement('pubDate', date('r')));
$item->appendChild(new DOMElement('link', $directLinkToItem));
// Add the CDATA
$item->appendChild(new DOMElement('description'))->appendChild(new DOMCdataSection($cdata));
// Now save back to file
$dom->save($filePath);
}
N.B. this now throws an exception if DOMDocument::load() fails - don't forget to catch it!

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