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());
Related
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>
I am trying to parse XML with PHP. The XML is a response from ebay getsellerlist api, and is structured like so:
<!--?xml version="1.0" encoding="UTF-8"?-->
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</pictureurl>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>
My php is as follows:
<?
$xml = '<!--?xml version="1.0" encoding="UTF-8"?--><getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents"><timestamp>2016-08-11T14:17:39.869Z</timestamp><ack>Success</ack><version>967</version><build>E967_CORE_APISELLING_17965876_R1</build><itemarray><item><itemid>itemid1</itemid><listingdetails><viewitemurl>itemurl1</viewitemurl></listingdetails><primarycategory><categoryid>categoryid1</categoryid><categoryname>categoryname1</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url1</galleryurl><photodisplay>thumbnail1</pictureurl><pictureurl>picture1</pictureurl></picturedetails></item><item><itemid>itemid2</itemid><listingdetails><viewitemurl>itemurl2</viewitemurl></listingdetails><primarycategory><categoryid>categoryid2</categoryid><categoryname>categoryname2</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url2</galleryurl><photodisplay>thumbnail2</pictureurl><pictureurl>picture2</pictureurl></picturedetails></item></itemarray></getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);
?>
When I run it, I get a blank page, no errors, nothing.
If I check $titles length using count(), it comes back as zero.
For some reason it is not getting the title node (or any other nodes) and I can't figure out how to parse the xml string with php and get the node values.
Any help most appreciated, if the question is vague or lacking detail, please let me know and I will correct it.
The XML isn't valid:
Unable to parse any XML input. org.jdom2.input.JDOMParseException: Error on line 2: The element type "photodisplay" must be terminated by the matching end-tag "".
And that's only after you remove the comments in your XML declaration:
<!--?xml version="1.0" encoding="UTF-8"?-->
shoud be
<?xml version="1.0" encoding="UTF-8"?>
Working demo:
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</photodisplay>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);
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');
Hello to all i have a little problem, i have one array like this
$slike=array('1.jpg','2.jpg')
And another XML that looks like this
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
</settings>
How to insert $slike in that XML, that new XML looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image>
<image>2.jpg</image>
</settings>
Txanks in advance
No idea into which problem you did run, but it's rather trivial using an XML library, e.g. even with SimpleXML in your case:
$slike = array('1.jpg','2.jpg');
$name = 'image';
$doc = new SimpleXMLElement($xml);
foreach($slike as $file) {
$doc->addChild($name, $file);
}
echo $doc->asXML();
The $xml in this example is the xml string from your question. Output:
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image><image>2.jpg</image></settings>
What about something like this:
header("Content-Type: text/xml; charset=utf-8"); // added this line - that way the browser will render it as XML
$slike = array('1.jpg','2.jpg');
$xml = "<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>";
foreach($slike as $s){
$xml.= "<image>".$s."</image>"; // create a new <image> node for each image in array
}
$xml .= "</settings>";
print_r($xml);
Outputs this:
<?xml version='1.0' encoding='UTF-8'?>
<settings>
<show_context_menu>yes</show_context_menu>
<hide_buttons_delay>2</hide_buttons_delay>
<thumbs_width>200</thumbs_width>
<horizontal_space_btween_buttons>0</horizontal_space_btween_buttons>
<buttons_margins>0</buttons_margins>
<image>1.jpg</image>
<image>2.jpg</image>
</settings>
http://php.net/manual/en/book.simplexml.php
The syntax looks something like this for your example
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
foreach($element as $key => $val) {
echo "{$key}: {$val}";
}
}
Ive been trying every way possible to create cdata entries in my xml. My latest attempt is as follows. I can't even get passed for the first statement where im creating a new DOMDocument. Any ideas?
<?php
$xml = '
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
';
$dom = new DOMDocument;
$dom->loadXML($xml);
$xml = simplexml_import_dom($dom);
print "working";
?>
You should not have any characters before the XML declaration. Remove the line break at $xml = '.
The neatest solution would be to use heredoc syntax:
$xml = <<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
XML;
Have a look at: DOMDocument::createCDATASection
$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
</cars>
';
$dom = new DOMDocument;
$dom->loadXML($xml);
$cdataNode = $dom->createCDATASection('<&>');
$dom->documentElement->appendChild($cdataNode);
echo $dom->saveXml();
Output:
<?xml version="1.0" encoding="ISO-8859-1"?>
<cars>
<make name="Ford">
<model>Mustang</model>
</make>
<make name="Honda">
<model>Accord</model>
</make>
<![CDATA[<&>]]></cars>