formatted xml file using php - php

i am using following code to create xml file using php
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$root = $doc->createElement('alerts');
$root = $doc->appendChild($root);
$alert = $doc->createElement('alert');
$alert = $root->appendChild($alert);
$id = $doc->createElement('id');
$id_text = $doc->createTextNode($api_id);
$id->appendChild($id_text);
$alert->appendChild($id);
$msg_type = $doc->createElement('msg_type');
$msg_type_text = $doc->createTextNode(1);
$msg_type->appendChild($msg_type_text);
$alert->appendChild($msg_type);
$doc->save($filename);
it saves xml file well formatted like this
<?xml version="1.0"?>
<alerts>
<alert>
<id>22</id>
<msg_type>1</msg_type>
</alert>
</alerts>
but when i append tags in existing file with following code it will not formatted
$doc = new DOMDocument();
$doc->formatOutput = true;
$xml = file_get_contents($filename);
$doc->loadXML($xml);
$root = $doc->firstChild;
$alert = $doc->createElement('alert');
$alert = $root->appendChild($alert);
$id = $doc->createElement('id');
$id_text = $doc->createTextNode($api_id);
$id->appendChild($id_text);
$alert->appendChild($id);
$msg_type = $doc->createElement('msg_type');
$msg_type_text = $doc->createTextNode(1);
$msg_type->appendChild($msg_type_text);
$alert->appendChild($msg_type);
$doc->save($filename);
xml file format will be like this
<alerts>
<alert>
<id>3</id>
<msg_type>1</msg_type>
<msg>Api Name:Loop LM (H-PO) has low credit.</msg>
<url>common/api/view_sms_api_list.php</url>
<status>0</status>
<create_date>1387351877</create_date>
</alert>
<alert><id>6</id><msg_type>1</msg_type></alert><alert><id>14</id><msg_type>1</msg_type></alert><alert><id>24</id><msg_type>1</msg_type></alert></alerts>
it will continue in single line when i append a alert tag in this xml file. what is the problem?
thanks in advance.

Add $doc->preserveWhiteSpace = false; before load your doc $doc->loadXML($xml);

Related

How to add more than one Element in the same Attribute - XML (PHP Code)?

I have a PHP code that is running well, however not as expected.
F.Y.I: It´s running a function that is collecting submitted data from a form. (piece of code not included here, cause it´s OK).
I need to have 2 fields inside "Dados": name and email, however only email is being recorded.
What should I do? Any clue?
My actual PHP code:
function my_generate_xml($posted_data)
$domDocument = new DOMDocument('1.0', 'ISO-8859-1');
$domDocument->formatOutput = true;
// build maximizer xml file
$xml_root = $domDocument->createElement('moduledata');
$xmlEntity = $domDocument->createElement('entity');
$xmlEntityTN = $domDocument->createAttribute('tablename');
$xmlEntityTN->value = 'Ent';
$xmlEntityFN = $domDocument->createAttribute('formatname');
$xmlEntityFN->value = 'Curriculum';
$xmlEntity->appendChild($xmlEntityTN);
$xmlEntity->appendChild($xmlEntityFN);
$xmlDefine = $domDocument->createElement('define');
$xmlDefine->nodeValue = $posted_data['nome'];
$xmlDefineN = $domDocument->createAttribute('name');
$xmlDefineN->value = 'ParamNome';
$xmlDefine->appendChild($xmlDefineN);
$xmlEntity->appendChild($xmlDefine);
$xmlSiga = $domDocument->createElement('SigaFiles');
$xmlSigaDN = $domDocument->createAttribute('Text');
$xmlSigaDN->value = 'SQG';
$xmlSiga->appendChild($xmlSigaDN);
// create node for current dados
$xml_dados = $domDocument->createElement('Dados');
$domElement = $domDocument->createElement('attribute',$posted_data['nome']);
$domElement = $domDocument->createElement('attribute',$posted_data['email']);
$domAttribute = $domDocument->createAttribute('domainname');
// Value for the created attribute
$domAttribute->value = 'Nome';
$domAttribute->value = 'Email';
$domElement->appendChild($domAttribute);
$xml_dados->appendChild($domElement);
$xmlSiga->appendChild($xml_dados);
$xmlEntity->appendChild($xmlSiga);
$xml_root->appendChild($xmlEntity);
$domDocument->appendChild($xml_root);
Desired XML output format:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<moduledata>
<entity tablename="Ent" formatname="Curriculum">
<define name="ParamNome">Thomas Edison</define>
<SigaFiles Text="SQG">
<Dados>
<attribute domainname="Nome">Thomas Edison</attribute>
<attribute domainname="Email">thomas.edison#gmail.com</attribute>
</Dados>
</SigaFiles>
</entity>
</moduledata>
Actual XML output format:
<?xml version="1.0" encoding="ISO-8859-1"?>
<moduledata>
<entity tablename="Ent" formatname="Curriculum">
<define name="ParamNome">Thomas Edison</define>
<SigaFiles Text="SQG">
<Dados>
<attribute domainname="Email">thomas.edison#gmail.com</attribute>
</Dados>
</SigaFiles>
</entity>
</moduledata>
Actual XML output format: (UPDATED)
<?xml version="1.0" encoding="ISO-8859-1"?>
<moduledata>
<entity tablename="Ent" formatname="Curriculum">
<define name="Thomas Edison">nome</define>
<SigaFiles Text="SQG">
<Dados>
<attribute domainname="Nome">Thomas Edison</attribute>
<attribute domainname="Email">thomas.edison#gmail.com</attribute>
</Dados>
</SigaFiles>
</entity>
</moduledata>
PHP Code (Updated)
<?php
function my_generate_xml($posted_data)
{
$domDocument = new DOMDocument('1.0', 'ISO-8859-1');
$domDocument->formatOutput = true;
// build maximizer xml file
$xml_root = $domDocument->createElement('moduledata');
$xmlEntity = $domDocument->createElement('entity');
$xmlEntityTN = $domDocument->createAttribute('tablename');
$xmlEntityTN->value = 'Ent';
$xmlEntityFN = $domDocument->createAttribute('formatname');
$xmlEntityFN->value = 'Curriculum';
$xmlEntity->appendChild($xmlEntityTN);
$xmlEntity->appendChild($xmlEntityFN);
$xmlDefine = $domDocument->createElement('define');
$xmlDefine->nodeValue = $posted_data['nome'];
$xmlDefineN = $domDocument->createAttribute('name');
$xmlDefineN->value = 'ParamNome';
$xmlDefine->appendChild($xmlDefineN);
$xmlEntity->appendChild($xmlDefine);
$xmlSiga = $domDocument->createElement('SigaFiles');
$xmlSigaDN = $domDocument->createAttribute('Text');
$xmlSigaDN->value = 'SQG';
$xmlSiga->appendChild($xmlSigaDN);
// create node for current dados
$xml_dados = $xmlSiga->appendChild($domDocument->createElement('Dados'));
$domElement = $xml_dados->appendChild($domDocument->createElement('attribute'));
$domElement->appendChild($domDocument->createTextNode($posted_data['nome']));
$domElement->setAttribute('domainname', 'Nome');
$domElement = $xml_dados->appendChild($domDocument->createElement('attribute'));
$domElement->appendChild($domDocument->createTextNode($posted_data['email']));
$domElement->setAttribute('domainname', 'Email');
$domDocument->appendChild($domElement);
$xmlSiga->appendChild($domDocument);
$xmlEntity->appendChild($xmlSiga);
$xml_root->appendChild($xmlEntity);
$domDocument->appendChild($xml_root);
// save it as a file for further processing
$content = chunk_split(base64_encode($domDocument->saveXML()));
$uploads = wp_upload_dir();
$domDocument->save($uploads['basedir'].'/prorh/'.(int)microtime(true).'.xml');
}
?>
Consider reorganizing your routine and append elements after their creation and not save all appendChild calls at the end. Since you reuse the same variable names keep all components (element, attribute, values) together. Recall XML is a tree structure that grows from the root:
// build maximizer xml file
$domDocument = new DOMDocument('1.0', 'ISO-8859-1');
$domDocument->formatOutput = true;
// moduledata root element
$xml_root = $domDocument->createElement('moduledata');
$domDocument->appendChild($xml_root);
// entity element
$xmlEntity = $domDocument->createElement('entity');
$xml_root->appendChild($xmlEntity);
$xmlEntityTN = $domDocument->createAttribute('tablename');
$xmlEntityTN->value = 'Ent';
$xmlEntityFN = $domDocument->createAttribute('formatname');
$xmlEntityFN->value = 'Curriculum';
$xmlEntity->appendChild($xmlEntityTN);
$xmlEntity->appendChild($xmlEntityFN);
// define element
$xmlDefine = $domDocument->createElement('define');
$xmlEntity->appendChild($xmlDefine);
$xmlDefine->nodeValue = $posted_data['nome'];
$xmlDefineN = $domDocument->createAttribute('name');
$xmlDefineN->value = 'ParamNome';
$xmlDefine->appendChild($xmlDefineN);
// SigaFiles element
$xmlSiga = $domDocument->createElement('SigaFiles');
$xmlEntity->appendChild($xmlSiga);
$xmlSigaDN = $domDocument->createAttribute('Text');
$xmlSigaDN->value = 'SQG';
$xmlSiga->appendChild($xmlSigaDN);
// dados element
$xml_dados = $domDocument->createElement('Dados');
$xmlSiga->appendChild($xml_dados);
// attribute child nodes
$domElement = $domDocument->createElement('attribute', $posted_data['nome']);
$domAttribute = $domDocument->createAttribute('domainname');
$domAttribute->value = 'Nome';
$domElement->appendChild($domAttribute);
$xml_dados->appendChild($domElement);
$domElement = $domDocument->createElement('attribute', $posted_data['email']);
$domAttribute = $domDocument->createAttribute('domainname');
$domAttribute->value = 'Email';
$domElement->appendChild($domAttribute);
$xml_dados->appendChild($domElement);
// OUTPUT TREE TO STRING
header("Content-type: text/xml");
echo $domDocument->saveXML();
You override the $domElement variable without appending the node.
// create node for current dados
$xml_dados = $domDocument->createElement('Dados');
$domElement = $domDocument->createElement('attribute',$posted_data['nome']);
$domElement = $domDocument->createElement('attribute',$posted_data['email']);
$domAttribute = $domDocument->createAttribute('domainname');
I suggest nesting the create* calls inside appendChild() calls.
// create node for current dados
$xml_dados = $xmlSiga->appendChild($domDocument->createElement('Dados'));
$domElement = $xml_dados->appendChild($domDocument->createElement('attribute'));
$domElement->appendChild($domDocument->createTextNode($posted_data['nome']));
$domElement->setAttribute('domainname', 'Nome');
$domElement = $xml_dados->appendChild($domDocument->createElement('attribute'));
$domElement->appendChild($domDocument->createTextNode($posted_data['email']));
$domElement->setAttribute('domainname', 'Email');
You do not need to create attributes as nodes, DOMElement::setAttribute() works just fine for that. But you should create text content as nodes. The second argument of DOMDocument::createElement() is broken and escapes only some special characters.

How do I edit an XML file in SimpleXML, based on the contents of the XML, if there are multiple values of the same tag?

Say I have an XML file like this.
<users>
<user>
<username>desbest</username>
<email>desbest#example.com</email>
<password>testpass1</password>
</user>
<user>
<username>demo</username>
<email>nobody#example.com</email>
<password>demo</password>
</user>
</users>
How do I use XPath to select the desbest user, then use php to edit the password under the desbest user, and save it as a file?
I have searched Google and Stack Overflow and I haven't found the answer.
Here is my current code.
// print_r($xml);
$newpass = "mynewpass";
// $newpass = password_hash($newpass, PASSWORD_DEFAULT);
$nodes = $xml->xpath(sprintf(" //users/user[(username = \"$myusername\")] "));
// print_r($nodes);
// $nodes[0]->password = "$newpass";
$domnode = dom_import_simplexml($nodes[0]);
$nodepath = $domnode->getNodePath();
// $xml = $xml->$nodepath->password = $newpass;
// $danodepath = $nodes[0]->getNodePath();
// print_r($nodes);
// $xml->users->user["(username = \"$myusername\")"] = "$newpass";
print_r($xml);
echo "<hr>";
print_r($nodepath);
You can achieve this just with SimpleXML - you don't need to involve DOMDocument at all.
The xpath method returns the <user> element you're looking for. You can then modify it simply by updating the password property (or add new ones, or attributes, etc). This updates the underlying SimpleXMLElement object, which you can then write back to the file as a string using asXML.
$filename = 'file.xml';
$sxml = simplexml_load_file($filename);
$username = "desbest";
$user = $sxml->xpath("./user[./username = '{$username}']")[0];
$user->password = 'testpassCHANGED';
file_put_contents($filename, $sxml->asXML());
See https://eval.in/923654 for an example
Example with DOMDocument:
$source = '<users>
<user>
<username>desbest</username>
<email>desbest#example.com</email>
<password>testpass1</password>
</user>
<user>
<username>demo</username>
<email>nobody#example.com</email>
<password>demo</password>
</user>
</users>';
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($source);
$xpath = new DOMXPath($dom);
$myusername = htmlspecialchars("desbest", ENT_XML1 | ENT_QUOTES, 'UTF-8');
$expression = sprintf('/users/user[(username="%s")]', $myusername);
$users = $xpath->query($expression);
if($users->length) {
$user = $users->item(0);
$password = $xpath->query('password', $user)->item(0);
$password->nodeValue = 'new password';
}
file_put_contents('filename.xml', $dom->saveXML());

append XML tree as child to another XML, using PHP

I want to add an XML tree into another XML, and I have tried with following code which is not working:
<?php
$str1 = '<parent>
<name>mrs smith</name>
</parent>';
$xml1 = simplexml_load_string($str1);
print_r($xml1);
$str2 = '<tag>
<child>child1</child>
<age>3</age>
</tag>';
$xml2 = simplexml_load_string($str2);
print_r($xml2);
$xml1->addChild($xml2);
print_r($xml1);
?>
Expect output XML:
<parent>
<name>mrs smith</name>
<tag>
<child>child1</child>
<age>3</age>
</tag>
</parent>
Please assist me.
You can use DOMDocument::importNode
<?php
$str2 = '<tag>
<child>child1</child>
<age>3</age>
</tag>';
$str1 = '<parent>
<name>mrs smith</name>
</parent>';
$tagDoc = new DOMDocument;
$tagDoc->loadXML($str2);
$tagNode = $tagDoc->getElementsByTagName("tag")->item(0);
//echo $tagDoc->saveXML();
$newdoc = new DOMDocument;
$newdoc->loadXML($str1);
$node = $newdoc->importNode($tagNode, true);
$newdoc->documentElement->appendChild($node);
echo $newdoc->saveXML();die;

XML create node before another PHP

I have a XML file and I'm trying to insert a new node between two others with PHP script.
XML file:
<playlistLog>
<hour>
<track>
<type>take</type>
<url>URL</url>
<title>1473869236.wav</title>
<mix>0</mix>
</track>
(...)
</hour>
</playlistLog>
PHP file:
$xmldoc = new DOMDocument();
$xmldoc->load('../logs/log14-09-2016.xml');
$elem = $xmldoc->getElementsByTagName("track");
$track = $xmldoc->createElement('track');
$type = $xmldoc->createElement('type', 'take');
$track->appendChild($type);
$url = $xmldoc->createElement('url', 'url');
$track->appendChild($url);
$title = $xmldoc->createElement('title', 'title');
$track->appendChild($title);
$mix = $xmldoc->createElement('mix', 'mix');
$track->appendChild($mix);
$xmldoc->documentElement->insertBefore($track,$elem[660]);
$xmldoc->save('../logs/log14-09-2016.xml');
I'm trying to insert the new node before "track" tag number 660 but when I try to open the php file it doesn't work at all.
Can anybody tell me what I am doing wrong?
SOLUTION:
After #ThW response I change a bit what he wrotes and finally the code is doing right:
$document = new DOMDocument();
$document->preserveWhiteSpace = FALSE;
$document->load('../logs/log14-09-2016.xml');
$xpath = new DOMXpath($document);
$previousTrack = $xpath->evaluate('/playlistLog/hour/track')->item(659);
$newTrack = $previousTrack->parentNode->insertBefore($document->createElement('track'),$previousTrack);
$newTrack
->appendChild($document->createElement('type'))
->appendChild($document->createTextNode('take'));
$document->formatOutput = TRUE;
echo $document->save('../logs/log14-09-2016.xml');
$elem[660] is the 661st element node with the tag name track. But its parent node is not the document element. Here is another hour ancestor between. The node you're providing to insertBefore() has a different parent then the node you're adding the new element to.
You can use the $parentNode property to make sure that you append to that node.
Additionally I suggest using Xpath to fetch the track node.
$xml = <<<'XML'
<playlistLog>
<hour>
<track>
<type>take</type>
<url>URL</url>
<title>1473869236.wav</title>
<mix>0</mix>
</track>
</hour>
</playlistLog>
XML;
$document = new DOMDocument();
$document->preserveWhiteSpace = FALSE;
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$previousTrack = $xpath->evaluate('/playlistLog/hour/track[1]')->item(0);
$newTrack = $previousTrack
->parentNode
->insertBefore(
$document->createElement('track'),
$previousTrack
);
$newTrack
->appendChild($document->createElement('type'))
->appendChild($document->createTextNode('take'));
$document->formatOutput = TRUE;
echo $document->saveXml();

XML Parsing Error

here i am creating xml file dynamically at run time but i m getting error
XML Parsing Error: junk after document element
Location: http://localhost/tam/imagedata.php?imageid=8
Line Number 9, Column 1:
^
$id=$_GET['imageid'];
$dom = new DomDocument('1.0');
$query="select * from tbl_image_gallery where imageId='$id'";
$select=mysql_query($query);
while($res=mysql_fetch_array($select))
{
$content = $dom->appendChild($dom->createElement('content'));
$image = $content->appendChild($dom->createElement('image'));
$small_image_path = $image->appendChild($dom->createElement('small_image_path'));
$small_image_path->appendChild($dom->createTextNode("load/images/small/".$res['image']));
$big_image_path = $image->appendChild($dom->createElement('big_image_path'));
$big_image_path->appendChild($dom->createTextNode("load/images/big/".$res['image']));
$description = $image->appendChild($dom->createElement('description'));
$description->appendChild($dom->createTextNode($res['description']));
$dom->formatOutput = true;
}
echo $test1 = $dom->saveXML();
and xml format is
<?xml version="1.0"?>
<content>
<image>
<small_image_path>load/images/small/1.jpg</small_image_path>
<big_image_path>load/images/big/1.jpg</big_image_path>
<description>hgjghj</description>
</image>
<image><small_image_path>load/images/small/2.jpg</small_image_path><big_image_path>load/images/big/2.jpg</big_image_path><description>fgsdfg</description></image><image><small_image_path>load/images/small/3.jpg</small_image_path><big_image_path>load/images/big/3.jpg</big_image_path><description>sdfgsdfg</description></image><image><small_image_path>load/images/small/4.jpg</small_image_path><big_image_path>load/images/big/4.jpg</big_image_path><description>gsbhsg</description></image><image><small_image_path>load/images/small/4.jpg</small_image_path><big_image_path>load/images/big/4.jpg</big_image_path><description>gsbhsg</description></image><image><small_image_path>load/images/small/avatar.jpg</small_image_path><big_image_path>load/images/big/avatar.jpg</big_image_path><description></description></image></content>
Can it be that you are posting html code into the description field?
Could be usefull to add a CDataSection instead of a TextNode
$cdata = $dom->createCDATASection($res['description']);
$image->appendChild($cdata);

Categories