How to append multiple XML files - php

I have a large XML file which takes forever to load on external FTP editor so I would like to split it into several files.
I use simplexml_load_file but couldn't make it load multiple files into same array.
XML files has the same structure, here's a sample of each file:
a.xml:
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>user</admin_user_type>
<show_in_menu>True</show_in_menu>
<title>Dashboard</title>
<vertical_report>True</vertical_report>
</query>
</queries>
b.xml:
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>admin</admin_user_type>
<show_in_menu>false</show_in_menu>
<title>Profile Element</title>
<input_name>Id</input_name>
<input_type>hidden</input_type>
</query>
</queries>
There are about 200 queries in 7,000 lines between the two files.
The code fails on the foreach below:
$xml = read_xml_files();
foreach($xml->children() as $xml) {
...
...
}
Below is what I've taken from Nigel's suggestion:
function read_xml_files() {
$target = new DOMDocument();
$target->loadXML('<base />');
mergeFile($target, XML_FILES_FOLDER."a.xml");
mergeFile($target, XML_FILES_FOLDER."b.xml");
$xml = simplexml_import_dom($target);
return $xml->asXML();
}
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->childNodes as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
Thanks for any suggestion!

If you use DOMDocument to do the main merging part...
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->childNodes as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
$target = new DOMDocument();
$target->loadXML('<base />');
mergeFile($target, "file1.xml");
mergeFile($target, "file2.xml");
$xml = simplexml_import_dom($target);
echo $xml->asXML();
At the end $xml contains the merged files.
Note that this adds another level to the document (unless I know the type of contents it's difficult to do anything else). So in this case you will get something like...
file1.xml
<?xml version="1.0" encoding="UTF-8"?>
<A>A</A>
file2.xml
<?xml version="1.0" encoding="UTF-8"?>
<B>B</B>
Result will be
<?xml version="1.0"?>
<base>
<A>A</A>
<B>B</B>
</base>
Update:
You could also try...
function read_xml_files() {
$target = new DOMDocument();
$target->loadXML('<queries />');
mergeFile($target, "NewFile.xml");
mergeFile($target, "NewFile1.xml");
$xml = simplexml_import_dom($target);
return $xml->asXML();
}
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->getElementsByTagName("query") as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
This merges the file so that the result is
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>user</admin_user_type>
<show_in_menu>True</show_in_menu>
<title>Dashboard</title>
<vertical_report>True</vertical_report>
</query>
<query>
<admin_user_type>admin</admin_user_type>
<show_in_menu>false</show_in_menu>
<title>Profile Element</title>
<input_name>Id</input_name>
<input_type>hidden</input_type>
</query>
</queries>

Related

how to merge xml files with root attributes?

I have several xml files, and they all have attributes in root.
More or less this way:
FILE1.XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<item_root id="item01" name="Item 01">
<child>content 01</child>
</item_root>
FILE2.XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<item_root id="item02" name="Item 02">
<child>content 02</child>
</item_root>
... and so on.
I need to merge all the files in one, dynamically with php.
But as a result of what I'm doing, I can't get the root attributes.
The result looks something like this:
<?xml version="1.0"?>
<itens>
<item_root>
<child>content 01</child>
</item_root>
<item_root>
<child>content 02</child>
</item_root>
</itens>
But it should look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<itens>
<item_root id="item01" name="Item 01">
<child>content 01</child>
</item_root>
<item_root id="item02" name="Item 02">
<child>content 02</child>
</item_root>
</itens>
My merge code looks like this:
<?php
$files= array(
'xmlitens/file1.xml',
'xmlitens/file2.xml'
);
$dom = new DOMDocument();
$itens = $dom->createElement('itens');
foreach ($files as $filename) {
$fileaddDom = new DOMDocument();
$fileaddDom->load($filename);
$itemroot = $dom->createElement('item_root');
if ($fileaddDom->documentElement) {
foreach ($fileaddDom->documentElement->childNodes as $node) {
$itemroot->appendChild(
$dom->importNode($node, TRUE)
);
}
}
$itens->appendChild($itemroot);
}
$dom->appendChild($itens);
?>
Is there an easy method to do this?
After I posted the question, the answer miraculously appeared to me.
Here is the solution I found:
$files= array(
'xmlitens/file1.xml',
'xmlitens/file2.xml'
);
$dom = new DOMDocument();
$itens = $dom->createElement('itens');
foreach ($files as $filename) {
$fileaddDom = new DOMDocument();
$fileaddDom->load($filename);
//This is the line that solves everything.
$node = $fileaddDom->getElementsByTagName("item_root")->item(0);
if ($fileaddDom->documentElement) {
$itens->appendChild( $dom->importNode($node, true) );
}
}
$dom->appendChild($itens);
Header('Content-type: text/xml');
print_r($dom->saveXML());

PHP XML: how to use createCDataSection() properly

I am trying to create an xml dynamically using domDocument.
What I would like to obtain is following:
<?xml version="1.0"?>
<books>
<book>
<content>
<name><![CDATA[dddd]]></name>
</content>
</book>
</books>
Unfortunatelly the script below does not show the output as excepted.
$xml = new DOMDocument('1.0');
$xml->formatOutput = true;
$books = $xml->createElement('books');
$xml->appendChild($books);
$book = $xml->createElement('book');
$books->appendChild($book);
$inside = $xml->createElement('content');
$book->appendChild($inside);
$xml->appendChild($inside)->appendChild($xml->createElement('name'))->appendChild($xml->createCDataSection('dddd'));
echo '<xmp>'.$xml->saveXML().'</xmp>';
This is the output
<?xml version="1.0"?>
<books>
<book>
<content>
<name><![CDATA[dddd]]></name>
<lastname><![CDATA[dddd]]></lastname>
....
</content>
I do not know how to use createCDataSection().
Like this?
$xml = new DOMDocument('1.0');
$xml->formatOutput = true;
$books = $xml->createElement('books');
$xml->appendChild($books);
$book = $xml->createElement('book');
$books->appendChild($book);
$content = $xml->createElement('content');
$book->appendChild($content);
$name = $xml->createElement('name');
$content->appendChild($name);
$name->appendChild($xml->createCDataSection('dddd'));
echo '<xmp>'.$xml->saveXML().'</xmp>';

Parsing an XML Caldav request in php

I'm trying to parse a request sent by ThunderBird to my CalDAV Server and from an example taken from stackoverflow with an XML like :
<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
<last_updated>2009-11-30 13:52:40</last_updated>
<product>
<element_1>foo</element_1>
<element_2>foo</element_2>
<element_3>foo</element_3>
<element_4>foo</element_4>
</product>
</products>
Using the function :
$XMLr = new XMLReader;
$XMLr->open('test.xml');
$doc = new DOMDocument;
// move to the first <product /> node
while ($XMLr->read() && $XMLr->name !== 'product');
// now that we're at the right depth, hop to the next <product/> until the end of the tree
$node = simplexml_import_dom($doc->importNode($XMLr->expand(), true));
// now you can use $node without going insane about parsing
$children = $node->children();
foreach($children as $child)
{
echo $child->getName();
echo "\n";
}
I get the answer "element_1 element_2 element_3 element_4 ", but if I use the same function on my request :
<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:resourcetype/>
<D:owner/>
<D:current-user-principal/>
<D:supported-report-set/>
<C:supported-calendar-component-set/>
<CS:getctag/>
</D:prop>
</D:propfind>
Replacing $XMLr->name !== 'product' by $XMLr->name !== 'D:prop' I get a white screen...
What do I do wrong ?
How can I get the answer "ressourcetype owner current-user-principal etc ..." ?
I try with XMLReader and simplexml_import_dom without success but in opposite, with DomDocument you can do it:
// Just for display test results
$break_line = '<br>';
if (php_sapi_name() === 'cli') {
$break_line = "\n";
}
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:resourcetype/>
<D:owner/>
<D:current-user-principal/>
<D:supported-report-set/>
<C:supported-calendar-component-set/>
<CS:getctag/>
</D:prop>
</D:propfind>';
$xml_document = new DomDocument(); // http://fr2.php.net/manual/fr/class.domdocument.php
$xml_document->loadXML($xml); // Or load file with $xml_document->load('test.xml);
$elements = $xml_document->getElementsByTagName('prop');
// $elements is a DOMNodeList object: http://fr2.php.net/manual/fr/class.domnodelist.php
foreach($elements as $element) {
// $element is a DOMElement object: http://fr2.php.net/manual/fr/class.domelement.php
$childs = $element->childNodes;
// $childs is DOMNodeList
foreach ($childs as $child) {
// $element is a DOMElement object
if ($child instanceof DOMElement) {
echo $child->nodeName . $break_line;
}
}
}
White screen normally means error.
Put error_reporting on E_ALL
error_reporting('E_ALL');

XML PHP Delete specific Child if?

I have a xml document looking like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<invites>
<invite>
<username>0</username>
<userid>0</userid>
</invite>
<invite>
<username>Danielle</username>
<gameid>87808</gameid>
</invite>
<invite>
<username>Petra</username>
<userid>978</userid>
</invite>
</invites>
</library>
Now, I want to delete the <invite> with Danielle but I am not sure how? I am using this right now but this will only delete the first record?
$file = 'my.xml';
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$xml = new DOMDocument("1.0", "ISO-8859-1");
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");
$root = $xml->documentElement;
$fnode = $root->firstChild;
$ori = $fnode->childNodes->item(0);
$fnode->removeChild($ori);
$xml->save($file);
I want to be able to delete depending on either gameid or userid. How do I go about this?
Thanks in advance :-)
You could use XPath to select all nodes that have a certain userid or gameid: http://www.w3schools.com/xpath/default.asp
Try this:
Using DOM & DOMXPath.
<?php
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// load the xml file
$dom->loadXML( '<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<invites>
<invite>
<username>0</username>
<userid>0</userid>
</invite>
<invite>
<username>Danielle</username>
<gameid>87808</gameid>
</invite>
<invite>
<username>Petra</username>
<userid>978</userid>
</invite>
</invites>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
//find all 'invite' nodes with username=Danielle and delete'em.
$node = $xpath->query("//invite[username='Danielle']");
// if found, append the new "value" node
if( $node->length ) {
foreach ($node as $n) {
$n->parentNode->removeChild( $n );
}
}
header('content-type: text/xml');
echo $dom->saveXML();
?>
Hope this helps.

Removing a node from xml file

I have an xml file
<?xml version="1.0"?>
<category>
<name>SWEATERS</name>
<name>WATCHES</name>
<name>PANTS</name>
<name>test</name>
<name>1</name>
</category>
How i can remove the node <name>test</name> using xpath ,xquery and php. I used this code
$name='test;
$xmlfile="config/shop_categories.xml";
$xml = simplexml_load_file($xmlfile);
$target = $xml->xpath('/category[name="'.trim($name).'"]');
print_r($target[0]);
if($target == false)
return;
$domRef = dom_import_simplexml($target[0]); //Select position 0 in XPath array
$domRef->parentNode->removeChild($domRef);
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
$dom->save($xmlfile);
But it is not working.
Pretty sure this is a duplicate, but am too lazy to find it. Here you go:
$xml = <<< XML
<?xml version="1.0"?>
<category>
<name>SWEATERS</name>
<name>WATCHES</name>
<name>PANTS</name>
<name>test</name>
<name>1</name>
</category>
XML;
$dom = new DOMDocument;
$dom->loadXML($xml);
$xPath = new DOMXPath($dom);
foreach($xPath->query('//name[text() = "test"]') as $node) {
$node->parentNode->removeChild($node);
}
echo $dom->saveXML();
Output:
<?xml version="1.0"?>
<category>
<name>SWEATERS</name>
<name>WATCHES</name>
<name>PANTS</name>
<name>1</name>
</category>

Categories