how to append node to parent node in xml file using php - php

i want to replace value of commented tags in xml file..how can i replace it using php ..given is file.xml
<SyncOpportunity_Input>
<SendConfirmationEmail/>
<UpdateToken/>
<CallingSystem>WS-TEST</CallingSystem>
<KeepLocking/>
<Error_spcCode/>
<EmailAddrOverwrite/>
<Opportunity>
//<IntegrationId>12</IntegrationId>
//<LoanWriterId>13</LoanWriterId>
//<Description>NA</Description>
<Applicant>
<integratedid1>28</integratedid1>
<FirstName>pri</FirstName>
<LastName>kj</LastName>
</Applicant>
<Property>
<integratedid>2</integratedid>
<Title>Mr</Title>
<DateOfBirth>1999-11-11</DateOfBirth>
</Property>
<Ownership>
<integratedid1>28</integratedid1>
<OwnershipPercentage>100</OwnershipPercentage>
</Ownership>
</Opportunity>
</SyncOpportunity_Input>
i dont want to create node each time.. i just want to replace the value of child node..as i am appending other tags dynamically using php.
here is my function.php file where I have appended other tags,where i have get tags and then created child nodes and the value of each tags is coming from our php form.As well each time we require to delete previous data.
$xml = new DOMDocument('1.0', 'utf-8');
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$nodesToDelete=array();
$pnodesToDelete=array();
//echo $fname;
$xml->load('file.xml');
$nodesToDelete=array();
$IntegrationId = rand(1,19);
$IntegrationId1 = rand(10,30);
$IntegrationId2 = rand(20,40);
$element = $xml->getElementsByTagName('Applicant')->item(0);
$pelement = $xml->getElementsByTagName('Property')->item(0);
$FirstName = $element->getElementsByTagName('FirstName')->item(0);
$LastName = $element->getElementsByTagName('LastName')->item(0);
//echo $timestamp;
//$oelement = $xml->getElementsByTagName('Opportunity');
$oelement = $xml->getElementsByTagName('Ownership')->item(0);;
$ownItem= $xml->createElement('Ownership');
$ownItem->appendChild($xml->createElement('integratedid1',$IntegrationId1 ));
$ownItem->appendChild($xml->createElement('OwnershipPercentage',100));
//$oItem->appendChild($xml->createElement('integratedid2',$IntegrationId2));
$newItem= $xml->createElement('Applicant');
$newItem->appendChild($xml->createElement('integratedid1',$IntegrationId1 ));
$newItem->appendChild($xml->createElement('FirstName', $_POST['fld_2260636']));
$newItem->appendChild($xml->createElement('LastName', $_POST['fld_4322743']));
$pnewItem= $xml->createElement('Property');
$pnewItem->appendChild($xml->createElement('integratedid',$IntegrationId ));
$pnewItem->appendChild($xml->createElement('Title', $_POST['fld_4755553']));
$pnewItem->appendChild($xml->createElement('DateOfBirth', $_POST['fld_1151367']));
//echo $newItem;
$xml->getElementsByTagName('Opportunity')->item(0)->appendChild($newItem);
$xml->getElementsByTagName('Opportunity')->item(0)->appendChild($pnewItem);
$xml->getElementsByTagName('Opportunity')->item(0)->appendChild($ownItem);
$nodesToDelete[]=$element;
$pnodesToDelete[]=$pelement;
$onodesToDelete[]=$oelement;

Related

How to add a child in xml without overwrite using php dom?

I have wrote this code in PHP to compile an XML file with parameters that are in URL.
But when the XML file is already created instead of adding the new data at the bottom of file inside the root element, overwrite it and delete all old data.
Where is the problem?
I have seen some examples online but I can't figure out how fix it.
I need to verify if file already exist and then add the element?
Or I need to read it and then add again the old elements and new?
I don't know very well dom so I can't figure out
<?php
$FOL = $_GET["FOL"];
$NUM = $_GET["NUM"];
$DAT = $_GET["DAT"];
$ZON = $_GET["ZON"];
$TIP = $_GET["TIP"];
$COM = $_GET["COM"];
$dom = new DOMDocument();
$dom->encoding = 'utf-8';
$dom->xmlVersion = '1.0';
$dom->formatOutput = true;
$xml_file_name = "$NUM.xml";
$xmlString = file_get_contents($xml_file_name);
$dom->loadXML($xmlString);
$loaded_xml = $dom->getElementsByTagName('Territorio');
$territorio_node = $dom->createElement('Territorio');
$child_node_NOM = $dom->createElement('NOM', "$NOM");
$territorio_node->appendChild($child_node_NOM);
$child_node_NUM = $dom->createElement('NUM', "$NUM");
$territorio_node->appendChild($child_node_NUM);
$child_node_DAT = $dom->createElement('DAT', "$DAT");
$territorio_node->appendChild($child_node_DAT);
$child_node_ZON = $dom->createElement('ZON', "$ZON");
$territorio_node->appendChild($child_node_ZON);
$dom->appendChild($territorio_node);
$child_node_TIP = $dom->createElement('TIP', "$TIP");
$territorio_node->appendChild($child_node_TIP);
$child_node_COM = $dom->createElement('COM', "$COM");
$territorio_node->appendChild($child_node_COM);
$dom->appendChild($territorio_node);
$dom->save($FOL.'/'.$xml_file_name);
echo "$xml_file_name creato correttamente";
?>
as per the comment: You should check that the root node of the XML file exists before calling createElement to generate a new one. To do that you can call getElementsByClassName and test whether the first entry is empty
ie: empty( $dom->getElementsByTagName('Territorio')[0] ) sort of thing...
If the root node exists we use that, otherwise add a new root to the document and continue
// check that the querystring has all the required parameters
if( isset(
$_GET['FOL'],
$_GET['NUM'],
$_GET['DAT'],
$_GET['ZON'],
$_GET['TIP'],
$_GET['COM']
)){
// the filename is generated from one of the querystring parameters
// - here the directory used is the same as the script running
$file=sprintf( '%s/%s.xml', __DIR__, $_GET['NUM'] );
// create an empty file if it does not exist
if( !file_exists( $file )){
file_put_contents( $file, '' );
}
clearstatcache();
// create the DOMDocument and set various options
libxml_use_internal_errors( true );
$dom=new DOMDocument('1.0','utf-8');
$dom->strictErrorChecking=false;
$dom->preserveWhiteSpace=true;
$dom->formatOutput=true;
$dom->recover=true;
// load the XML file directly rather than loading a string read from the original file.
$dom->load( $file );
// The ROOT node of the document ... does it exist? if not, create it and add to the DOM.
$root=$dom->getElementsByTagName('Territorio')[0];
if( empty( $root ) ){
$root=$dom->createElement('Territorio');
$dom->appendChild( $root );
}
// I added this part so that you can distinguish easily new elements
$record=$dom->createElement('record');
$root->appendChild( $record );
// add all the querystring parameters within the new record.
$record->appendChild( $dom->createElement('NUM', $_GET["NUM"] ) );
$record->appendChild( $dom->createElement('DAT', $_GET["DAT"] ) );
$record->appendChild( $dom->createElement('ZON', $_GET["ZON"] ) );
$record->appendChild( $dom->createElement('TIP', $_GET["TIP"] ) );
$record->appendChild( $dom->createElement('COM', $_GET["COM"] ) );
$record->appendChild( $dom->createElement('FOL', $_GET["FOL"] ) );
$dom->save( $file );
}
An example of the XML generated:
<?xml version="1.0" encoding="utf-8"?>
<Territorio>
<record>
<NUM>wibble</NUM>
<DAT>25/10/2022</DAT>
<ZON>europe</ZON>
<TIP>total</TIP>
<COM>94</COM>
<FOL>234</FOL>
</record>
<record>
<NUM>wibble</NUM>
<DAT>26/10/2022</DAT>
<ZON>europe</ZON>
<TIP>total</TIP>
<COM>96</COM>
<FOL>238</FOL>
</record>
</Territorio>
In the original code the file is saved to a location defined by another parameter in the querystring ( only just noticed that afterwards ) so rather than
$file=sprintf( '%s/%s.xml', __DIR__, $_GET['NUM'] );
you would likely want to do:
$file=sprintf( '%s/%s.xml', $_GET['FOL'], $_GET['NUM'] );
The root node of an XML document is called document element and here is an property for it. So you can just check if it is undefined. However an document can have only a single document element, so will need to modify the structure of your XML - for example add a "Territori" document element.
Do not use the second argument of the createElement() method or the $nodeValue property. Their escaping is broken - try adding a value with an &. Use $textContent or add a text node.
In modern DOM you can even just append() a string.
$NUM = "NUM";
$DAT = "DAT";
$ZON = "ZON";
$document = new DOMDocument('1.0', 'UTF-8');
// let the parser ignore existing indents
$document->preserveWhiteSpace = false;
$document->loadXML(getXMLString());
// fetch or create document element
$territori = $document->documentElement
?? $document->appendChild($document->createElement('Territori'));
// create/append an item element
$territori
->appendChild(
$territorio = $document->createElement('Territorio')
);
// create/append an element and set its text content
$territorio
->appendChild($document->createElement('NUM'))
->textContent = $NUM;
// create/append an element with a text child node
$territorio
->appendChild($document->createElement('DAT'))
->appendChild($document->createTextNode($DAT));
// create/append an element and a string (DOM Level 3)
$territorio
->appendChild($document->createElement('ZON'))
->append((string)$ZON);
// enable output formatting
$document->formatOutput = true;
echo $document->saveXML();
function getXMLString() {
return <<<'XML'
<?xml version="1.0"?>
<Territori>
<Territorio>
<NUM>NUM</NUM>
<DAT>DAT</DAT>
<ZON>DAT</ZON>
</Territorio>
</Territori>
XML;
}
For a more flexible approach to fetch nodes use Xpath expressions. Here is an example that checks if an Territorio with a specific NUM value exists:
$document = new DOMDocument('1.0', 'UTF-8');
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
if ($xpath->evaluate('count(//Territorio[NUM="NUM"]) > 0')) {
echo "Node exists";
}

DOMDocument not updating nodeValue

So I wrote a piece of code which is supposed to be editing the xml file. But it doesn't seem to work. I have checked everything and all data seems to come through, but somehow it does not update the nodes. Creating the xml file and the data works, adding data works too. But somehow I can't seem to update it.
if ($edit && isset($_POST["submit"])) {
$doc = new DomDocument('1.0');
$doc->validateOnParse = true;
$doc->load('data.xml');
$message = getElementById($_GET["id"], $doc);
$message->getElementsByTagName("title")->nodeValue = 'hey';
$message->getElementsByTagName("content")->nodeValue = $_POST["content"];
$target = $message->getElementsByTagName("target")->nodeValue = $_POST["target"];
$date1 = $message->getElementsByTagName("startDate")->nodeValue = $_POST["date1"];
$date2 = $message->getElementsByTagName("endDate")->nodeValue = $_POST["date2"];
$doc->formatOutput = true;
$doc->save('data.xml');
}
function getElementById($id, $doc)
{
$xpath = new DOMXPath($doc);
return $xpath->query("//*[#id='$id']")->item(0);
}
XML:
<message id="5a1c301ae5429" top="12px" left="12px" duration="20">
<title>hey</title>
<content>12345</content>
<target>2</target>
<startDate>27/11/2017 16:30</startDate>
<endDate>27/11/2017 16:50</endDate>
<media type="image" width="200px" height="200px" top="-20px" left="129px">
<uri>
localhost/xml/uploads/4215c27edf5ff51aee0def29f84949be.jpg
</uri>
</media>
</message>
When you call getElementsByTagName, this returns a list of nodes that match the tag name. So each time you access the value, you should use...
$message->getElementsByTagName("title")->item(0)->nodeValue = 'hey';
As you only have 1 of each tag, I've used ->item(0) to fetch the first node in the list.
Repeat the same logic for all times you need to access the elements.

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

Xml created in PHP node values and elements

I do not understand these node value things at all i am trying to replicate an xml design in php but having quite a bit of trouble the file i am trying to reproduce through php is.
<items>
<item>
<id></id>
<name></name>
<price></price>
<quantity></quantity>
<description></description>
<qonhold></qonhold>
<qsold></qsold>
</item>
</items>
And the PHP file to recreate this is almost all done
$dom = new DOMDocument("1.0");
// create root element
$root = $dom->createElement("Items");
$dom->appendChild($root);
$dom->formatOutput=true;
// create child element
$item = $dom->createElement("item");
$dom->appendChild($item);
// create text node
$id = $dom->createElement("id");
$root->appendChild($id);
$name = $dom->createElement("name");
$root->appendChild($name);
$price = $dom->createElement("price");
$root->appendChild($price);
$quantity = $dom->createElement("quantity");
$root->appendChild($quantity);
$description = $dom->createElement("description");
$root->appendChild($description);
$qonhold = $dom->createElement("qonhold");
$root->appendChild($qonhold);
$qsold = $dom->createElement("qsold");
$root->appendChild($qsold);
The problem i am having is its saving it all under "items" being the root.. but i can not get everything id, name, price, quantity, description, qonhold, qsold to save under just "item" which is saved under "items
You should use ->appendChild() on the item node created, not the root which is <items>:
// create child element
$item = $dom->createElement("item");
$dom->appendChild($item);
// create text node
$id = $dom->createElement("id");
$item->appendChild($id); // item->appendChild not $root->appendChild
Should look like this:
$dom = new DOMDocument("1.0");
// create root element
$root = $dom->createElement("Items");
$dom->appendChild($root);
$dom->formatOutput=true;
// create child element
$item = $dom->createElement("item");
$root->appendChild($item); // append to `<Items>`
// create text node
$id = $dom->createElement("id");
$item->appendChild($id); // append to `<item>`
$name = $dom->createElement("name");
$item->appendChild($name); // append to `<item>`
$price = $dom->createElement("price");
$item->appendChild($price); // append to `<item>`
$quantity = $dom->createElement("quantity");
$item->appendChild($quantity); // append to `<item>`
$description = $dom->createElement("description");
$item->appendChild($description); // append to `<item>`
$qonhold = $dom->createElement("qonhold");
$item->appendChild($qonhold); // append to `<item>`
$qsold = $dom->createElement("qsold");
$item->appendChild($qsold); // append to `<item>`

about php 5.x create xml by dom document

I'm using DOMDocument class of PHP to create a xml file, my code is:
$xmlObject = new DOMDocument('1.0', 'utf-8');
//root node -- books
$books = $xmlObject->createElement('books');
//book node
$book = $xmlObject->createElement('book');
//book node's attribute -- index
$index = new DOMAttr('index', '1');
$book->appendChild($index);
//name node
$name = $xmlObject->createElement('name', 'Maozedong');
//name node's attribute -- year
$year = new DOMAttr('year', '1920');
$name->appendChild($year);
$book->appendChild($name);
//story node
$story = $xmlObject->createElement('story');
$title = $xmlObject->createElement('title', 'Redrevolution');
$quote = $xmlObject->createElement('quote', 'LeaveoffHunan');
$story->appendChild($title);
$story->appendChild($quote);
$book->appendChild($story);
$books->appendChild($book);
if ($xmlObject->save('xml/books.xml') != false){
echo 'success';
}else{
echo 'error';
}
The content of books.xml is only one line:
<?xml version="1.0" encoding="utf-8"?>
the other node is non-existent. Are there any errors in my code?
I forget append the books node to $xmlObject.
add:
$xmlObject->appendChild($books);

Categories