Combining XML files in php - php

I am getting external xml files (through file exchange) and I am able to read and store in the database (php/mysql).
The xml files come zipped under different names and sometimes several files come together zipped in a folder
When the folder has only 1 xml file,I am able to successfully unzip and read the content using
$path = '/xmlFile';
//the xmlFile names are in this format : xmFile-00001235.xml,
//xmlFile-000012390.xml, etc. only first portions are consistent
foreach (glob($path.'/xmlFile-*.xml') as $filename)
{
$xml=file_get_contents($filename);
}
//store in database and unlink the xml file
This only works if the folder has one xml file, because I am un-linking the xml file after storage, it un-links all the files but only stores one
What would be the best approach; I am thinking of checking if the folder has more than 1 xml and combine the xml files? maybe a sample solution will really help,
The sample xml is as follows
xml1.xml
<sales>
<row id="000001" saleid="267158" amountSold="2000" />
<row id="000001" saleid="267159" amountSold="80.000" />
</sales>
xml2.xml
<sales>
<row id="000001" saleid="267160" amountSold="4000" />
<row id="000001" saleid="267161" amountSold="580" />
</sales>

Merging several files can be done something like...
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->getElementsByTagName("row") as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
$target = new DOMDocument();
$target->loadXML('<?xml version="1.0" encoding="utf-8"?><sales></sales>');
mergeFile($target, "NewFile.xml");
mergeFile($target, "NewFile1.xml");
mergeFile($target, "NewFile2.xml");
$target->save("out2.xml");
This allows you to keep on adding all of the files together and then saving them at the end.

Based on the answer in: Merge XML files in PHP
$doc1 = new DOMDocument();
$doc1->load('1.xml');
$doc2 = new DOMDocument();
$doc2->load('2.xml');
// get 'res' element of document 1
$res1 = $doc1->getElementsByTagName('items')->item(0); //edited res - items
// iterate over 'item' elements of document 2
$items2 = $doc2->getElementsByTagName('item');
for ($i = 0; $i < $items2->length; $i ++) {
$item2 = $items2->item($i);
// import/copy item from document 2 to document 1
$item1 = $doc1->importNode($item2, true);
// append imported item to document 1 'res' element
$res1->appendChild($item1);
}

Related

How to create one XML file for each record from a XML file export from MYSQL database?

Good day to everyone. I was exported the a set of data in xml from MYSQL database. But, I want to separate the existing xml file into 1 ROW in 1 XML file. The example is as below:
Exported XML result from database:
Filename: result01.xml
Script in file:
<ROWDATA>
<ROW>
<DOCKEY>57911</DOCKEY>
<DOCNO>MY1113</DOCNO>
<DOCDATE>20141201</DOCDATE>
</ROW>
<ROW>
<DOCKEY>57913</DOCKEY>
<DOCNO>MY1114</DOCNO>
<DOCDATE>20141201</DOCDATE>
</ROW>
<ROW>
<DOCKEY>57915</DOCKEY>
<DOCNO>MY1115</DOCNO>
<DOCDATE>20141201</DOCDATE>
</ROW>
<ROW>
<DOCKEY>57915</DOCKEY>
<DOCNO>MY1115</DOCNO>
<DOCDATE>20141201</DOCDATE>
</ROW>
<ROW>
<DOCKEY>57957</DOCKEY>
<DOCNO>MY1160</DOCNO>
<DOCDATE>20141201</DOCDATE>
</ROW>
</ROWDATA>
But what I need is to create one file per row:
Filename: 57911.MY1113.xml
XML in file:
<ROWDATA>
<ROW DOCKEY="57911" DOCNO="MY1113" DOCDATE="20141201">
</ROW></ROWDATA>
Filename: 57913.MY1114.xml
XML in file:
<ROWDATA>
<ROW DOCKEY="57913" DOCNO="MY1114" DOCDATE="20141201">
</ROW></ROWDATA>
Does anyone know if there's a simple way of creating multiple XML files
as I mentioned. Your feedback is highly appreciated.
Thank you very much.
So with PHP it would look something like this:
$outDir = 'path/to/output/dir';
$src = 'result01.xml';
// create the document and load our source xml file
$srcDom = new DOMDocument();
$srcDom->load($src);
// pull all the ROW elements with xpath
$rowFinder = new DOMXpath($srcDom);
$rows = $rowFinder->query('//ROW');
// loop over the ROWs
foreach($rows as $row) {
// create a new document for our export.
$outDoc = new DOMDocument();
// create a ROWDATA element for our root node
$outRoot = $outDoc->createElement('ROWDATA');
// import the ROW node (and all its descendents into the new document
$outRow = $outDoc->importNode($row, true);
$filename = array(
'DOCKEY' => '',
'DOCNO' => ''
);
foreach ($outRow->childNodes as $datum) {
// add the values for segements of the filename
if (array_key_exists($datum->nodeName, $filename)) {
$filename[$datum->nodeName] = $datum->nodeValue;
}
}
// append the ROW to ROWDATA
$outRoot->appendChild($outRow);
// append the ROWDATA to our document
$outDoc->appendChild($outRoot);
// save the xml to file using strtr to create the file name from
// our array of filename segments
$outDoc->save(strtr($outDir . '/DOCKEY.DOCNO.xml', $filename));
}

issues in writing xml files in php

I wrote a code in which i m writing new xml files depending on content of one xml file i have with me right now.
In xml file from which i m reading,there are 14 fragments with 3 -4 nodes each.I have to right 7 new xml files in this case,each containing 2 fragments from first file.
So that all xml files after writing should have 2 fragments each,totalling all to 14 fragments when all files combined.
But the code is not giving me the correct output
following is the code
<?php
$docOutput = new DOMDocument("1.0");
$root = $docOutput ->createElement("data");
$docOutput ->appendChild($root);
if(!$xml=simplexml_load_file('xmlfile.xml')){
trigger_error('Error reading XML file',E_USER_ERROR);
}
$array1=array();
$x=0;
foreach($xml as $syn)
{
for($i=$x*2;$i<($x+1)*2;$i++)
{
//$array1[] = $syn->productId;
echo $i;
echo "<br />";
echo $syn->productId;
$id = $docOutput ->createElement("PID");
$idText = $docOutput ->createTextNode($syn->productId);
$id->appendChild($idText);
$title = $docOutput ->createElement("PNAME");
$titleText = $docOutput ->createTextNode($syn->productname);
$title->appendChild($titleText);
$book = $docOutput ->createElement("Product");
$book->appendChild($id);
$book->appendChild($title);
$root->appendChild($book);
}
$docOutput ->formatOutput = true;
echo "<xmp>". $docOutput ->saveXML() ."</xmp>";
$docOutput ->save("mybooks$x.xml") or die("Error");
$x++;
}
//echo count($array1, COUNT_RECURSIVE);
?>
Following is one fragment of file,which i m reading
<?xml version="1.0"?>
<data>
<Product>
<PID>SGLDN7XJ2FPZH8G8</PID>
<PNAME>Miami Blues Aviator Sunglasses</PNAME>
</Product>
</data>
There are 14 Product fragments in file from which i m reading.After writing i should get 7 files with two fragments each.
Please help in correcting the code
The problem you've got is less with the code to read/write the XML but more just with the basic looping logic.
What you perhaps actually want is while iterating over the product nodes, to move the iteration ahead so you can put two product elements together. This works with a SimpleXMLIterator:
$xml = simplexml_load_string($buffer, 'SimpleXMLIterator');
foreach ($xml as $product) {
// output current element
printf("-+-%s\n", $product->asXML());
// move to next element
$xml->next();
$product = $xml->current();
// output next element
printf(" \- %s\n\n", $product->asXML());
}
With this XML input:
<?xml version="1.0"?>
<data>
<Product>1</Product>
<Product>2</Product>
<Product>3</Product>
<Product>4</Product>
</data>
The example outputs:
-+-<Product>1</Product>
\- <Product>2</Product>
-+-<Product>3</Product>
\- <Product>4</Product>
Online-Demo: https://eval.in/172918

for loop putting two similar entries in one loop in php

I wrote a code according to which I can write one XML file into number of XML files depending on number of records.
I have 14 records in one XML file having different tags in XML file.
I am trying to create XML files having having 2 records each, so in the end I should be having 7 XML files.
But instead that I'm getting 14 files only, each file having two similar records.
Following is my XML format, which is getting created dynamically. Format is coming correctly. But two similar entries are coming in each file. So instead of 7 its writing 14 files.
<?xml version="1.0"?>
<data>
<Product>
<PID>SGLDN7XJ2FPZH8G8</PID>
<PNAME>Miami Blues Aviator Sunglasses</PNAME>
</Product>
</data>
Following is my file which is making XML files. I think something is wrong in initializing the for loop:
$docOutput = new DOMDocument("1.0");
$root = $docOutput->createElement("data");
$docOutput->appendChild($root);
if (!$sxmlReading = simplexml_load_file('firstxml.xml')) {
throw new RuntimeException('Error reading XML file');
}
$x = 0;
foreach ($sxmlReading as $syn) {
for ($i = $x * 2; $i < ($x + 1) * 2; $i++) {
$id = $docOutput->createElement("PID");
$idText = $docOutput->createTextNode($syn->productId);
$id->appendChild($idText);
$title = $docOutput->createElement("PNAME");
$titleText = $docOutput->createTextNode($syn->productname);
$title->appendChild($titleText);
$book = $docOutput->createElement("Product");
$book->appendChild($id);
$book->appendChild($title);
$root->appendChild($book);
$docOutput->formatOutput = true;
echo "<xmp>" . $docOutput->saveXML() . "</xmp>";
$docOutput->save("xml$x.xml") or die("Error");
}
$x++;
}
Please check the code and highlight my mistake...
It is writing 14 files because you are calling the DOMDocument::save() method 14 times.
Sounds more like a typo to me honestly, I can not see anything wrong with that. PHP just does as you've written it to do.

XMLReader - Blank Page With No Errors

I'm trying to get the data from an XML file into an array so that I can import it via 'Magmi'. Using the following code, I'm working with a 3.6GB XML file.
<?php
$z = new XMLReader;
$z->open('wpcatsub.xml');
$doc = new DOMDocument;
// move to the first <App /> node
while ($z->read() && $z->name !== 'App');
// now that we're at the right depth, hop to the next <App/> until the end of the tree
while ($z->name === 'App')
{
// either one should work
//$node = new SimpleXMLElement($z->readOuterXML());
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
// now you can use $node without going insane about parsing
var_dump($node->element_1);
// go to next <product />
$z->next('App');
}
?>
When I load the PHP file, no errors appear -- the page is just blank. My XML data structure is below...
<App action="A" id="1">
<BaseVehicle id= "17491"/>
<Note><![CDATA[License Plate Lamp]]></Note>
<Qty>.000</Qty>
<PartType id= "10043"/>
<Part>W0133-1620896</Part>
<Product>
<PartNumber>W0133-1620896</PartNumber>
<BrandID>OES</BrandID>
<BrandDescription><![CDATA[Genuine]]></BrandDescription>
<WorldpacCategoryID>P9032</WorldpacCategoryID>
<Price>29.85</Price>
<ListPrice>33.17</ListPrice>
<Available>Y</Available>
<OEFlag>OEM</OEFlag>
<Weight>.10</Weight>
<Height>.7</Height>
<Width>4.4</Width>
<Length>4.4</Length>
<SellingIncrement>1</SellingIncrement>
<Popularity>D</Popularity>
<ImageURL><![CDATA[http://img.eautopartscatalog.com/live/W01331620896OES.JPG]]></ImageURL>
<ThumbURL><![CDATA[http://img.eautopartscatalog.com/live/thumb/W01331620896OES.JPG]]></ThumbURL>
</Product>
<ImageURL><![CDATA[http://img.eautopartscatalog.com/live/W01331620896OES.JPG]]></ImageURL>
<ThumbURL><![CDATA[http://img.eautopartscatalog.com/live/thumb/W01331620896OES.JPG]]></ThumbURL>
</App>
Is it stalling because of the size of the file? If so, isn't XMLReader supposed to work for large XML files? If nothing else, what other options would I have?
I suppose I could load the XML data into a database if needed and then use SELECT queries to build the array for the MAGMI import. Though I'm not sure how to import an XML file into a SQL database. If need be, I'll be happy to get guidance with that.

PHP - Retrieving Only Certain XML Nodes and Saving to a file

I am using PHP curl to retrive an xml file from a remote url and save it to a local file on my server. The structure is the following:
<Store Country="Ireland">
<EventsPoints>
<Event ID="1800" >
<ArtistIDs>
<ArtistID ID="109" Type="Primary" />
</ArtistIDs>
<CategoryID>1</CategoryID>
<Country>IRL</Country>
<PerformanceName>Music and Arts</PerformanceName>
<VenueID ID="197" />
</Event>
<Venues>
<Venue ID="197">
<City>Dublin</City>
<Country>IRL</Country>
<VenueName>ABC</VenueName>
<VenueNumber>22</VenueNumber>
</Venue>
</Venues>
The above xml blocks are stored in the same XML file. There are several Event blocks and several Venue blocks.
The problem i'm having is using PHP to access this large XML file and iterate through the Venue blocks retrieving only a Venue block with a certain ID specified via a parameter.
I then want to iterate through the event blocks - only retrieving the events matching this specified venue ID. I then want to save this to a file on the server.
I want to do this for each venue.
How do I go about doing the above?
EDIT:
For each Venue and events related to that venue, I just want to literally copy them to their own file - basically splitting down the larger file into individual files
$docSource = new DOMDocument();
$docSource->loadXML($xml);
$docDest = new DOMDocument();
$docDest->loadXML(file_get_contents('/var/www/html/xml/testfile.xml'));
$xpath = new DOMXPath($docSource);
$id = "197";
$result = $xpath->query('//Event/VenueID[#ID=$id]')->item(0); //Get directly the node you want
$result = $docDest->importNode($result, true); //Copy the node to the other document
$items = $docDest->getElementsByTagName('items')->item(0);
$items->appendChild($result); //Add the copied node to the destination document
echo $docDest->saveXML();
You are not showing the desired output format, so I will assume this generates what you want. If not, feel free to modify the code so it meets the desired output format. This along with the comments above should have all you need to get this working on your own.
// load Source document
$srcDom = new DOMDocument;
$srcDom->load('/var/www/html/xml/testfile.xml');
$xPath = new DOMXPath($srcDom);
// iterate over all the venues in the source document
foreach ($srcDom->getElementsByTagName('Venue') as $venue) {
// create a new destination document for the current venue
$dstDom = new DOMDocument('1.0', 'utf-8');
// add an EventsPoint element as the root node
$dstDom->appendChild($dstDom->createElement('EventsPoint'));
// import the Venue element tree to the new destination document
$dstDom->documentElement->appendChild($dstDom->importNode($venue, true));
// fetch all the events for the current venue from the source document
$allEventsForVenue = $xPath->query(
sprintf(
'/Store/EventsPoints/Event[VenueID/#ID=%d]',
$venue->getAttribute('ID')
)
);
// iterate all the events found in Xpath query
foreach ($allEventsForVenue as $event) {
// add event element tree to current destination document
$dstDom->documentElement->appendChild($dstDom->importNode($event, true));
}
// make output prettier
$dstDom->formatOutput = true;
// save XML to file named after venue ID
$dstDom->save(sprintf('/path/to/%d.xml', $venue->getAttribute('ID')));
}
This will create an XML file like this
<?xml version="1.0" encoding="utf-8"?>
<EventsPoint>
<Venue ID="197">
<City>Dublin</City>
<Country>IRL</Country>
<VenueName>ABC</VenueName>
<VenueNumber>22</VenueNumber>
</Venue>
<Event ID="1800">
<ArtistIDs>
<ArtistID ID="109" Type="Primary"/>
</ArtistIDs>
<CategoryID>1</CategoryID>
<Country>IRL</Country>
<PerformanceName>Music and Arts</PerformanceName>
<VenueID ID="197"/>
</Event>
</EventsPoint>
in the file 197.xml

Categories