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.
Related
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);
}
I have different XML files where I renamed for each XML file all individual tags, so that every XML file has the same tag name. That was easy because the function was customized for the XML file.
But instand of writing 7 new functions for each XML file now I want to check if a XML file has a specidifed child or not. Because if I want to say:
foreach ($items as $item) {
$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;
$price = $node->getElementsByTagName('price')->item(0)->textContent;
$url = $node->getElementsByTagName('url')->item(0)->textContent;
$publisher = $node->getElementsByTagName('publisher')->item(0)->textContent;
$category = $node->getElementsByTagName('category')->item(0)->textContent;
$platform = $node->getElementsByTagName('platform')->item(0)->textContent;
}
I get sometimes: PHP Notice: Trying to get property of non-object in ...
For example. Two different XML sheets. One contains publisher, category and platform, the other not:
XML 1:
<products>
<product>
<desc>This is a Test</desc>
<price>11.69</price>
<price_base>12.99</price_base>
<publisher>Stackoverflow</publisher>
<category>PHP</category>
</packshot>
<title>Check if child exists? - SimpleXML (PHP)</title>
<url>http://stackoverflow.com/questions/ask</url>
</product>
</products>
XML 2:
<products>
<product>
<image></image>
<title>Questions</title>
<price>23,90</price>
<url>google.de/url>
<platform>Stackoverflow</platform>
</product>
</products>
You see, sometimes one XML file contains publisher, category and platform but sometimes not. But it could also be that not every node of a XML file contains all attributes like in the first!
So I need to check for every node of a XML file individual if the node is containing publisher, category or/and platform.
How can I do that with SimpleXML?
I thought about switch case but at first I need to check which childs are contained in every node.
EDIT:
Maybe I found a solution. Is that a solution or not?
if($node->getElementsByTagName('platform')->item(0)){
echo $node->getElementsByTagName('platform')->item(0)->textContent . "\n";
}
Greetings and Thank You!
One way to rome... (working example)
$xml = "<products>
<product>
<desc>This is a Test</desc>
<price>11.69</price>
<price_base>12.99</price_base>
<publisher>Stackoverflow</publisher>
<category>PHP</category>
<title>Check if child exists? - SimpleXML (PHP)</title>
<url>http://stackoverflow.com/questions/ask</url>
</product>
</products>";
$xml = simplexml_load_string($xml);
#set fields to look for
foreach(['desc','title','price','publisher','category','platform','image','whatever'] as $path){
#get the first node
$result = $xml->xpath("product/{$path}[1]");
#validate and set
$coll[$path] = $result?(string)$result[0]:null;
#if you need here a local variable do (2 x $)
${$path} = $coll[$path];
}
#here i do array_filter() to remove all NULL entries
print_r(array_filter($coll));
#if local variables needed do
extract($coll);#this creates $desc, $price
Note </packshot> is an invalid node, removed here.
xpath syntax https://www.w3schools.com/xmL/xpath_syntax.asp
Firstly, you're over-complicating your code by switching from SimpleXML to DOM with dom_import_simplexml. The things you're doing with DOM can be done in much shorter code with SimpleXML.
Instead of this:
$node = dom_import_simplexml($item);
$title = $node->getElementsByTagName('title')->item(0)->textContent;
you can just use:
$title = (string)$item->title[0];
or even just:
$title = (string)$item->title;
To understand why this works, take a look at the SimpleXML examples in the manual.
Armed with that knowledge, you'll be amazed at how simple it is to see if a child exists or not:
if ( isset($item->title) ) {
$title = (string)$item->title;
} else {
echo "There is no title!";
}
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
I'm provided a XML file with this structure:
<items>
<item>
<images>
<image>A</image>
<image>B</image>
<image>C</image>
</images>
.
.
.
</item>
</items>
However the import function of my Shop requires the following format:
<items>
<item>
<images>
<image>A</image>
<image1>B</image>
<image2>C</image>
</images>
.
.
.
</item>
</items>
At first I was thinking I would do this simply in Java since it would be pretty easy to read line by line and restructure the document but I would love to have it so I can just visit a url and this is done for me.
Here is the approach I took:
<?php
$xml = simplexml_load_file('data.xml');
// Loop over items in original xml
for($i = 0; $i < count($xml->item); $i++)
{
$images;
if( ($c = count($xml->item[$i]->images->image)) > 1)
{
$images = $xml->item[$i]->images;
// Remove entry
unset($xml->item[$i]->images);
$xml->item[$i]->addChild('images');
for($y = 0; $y < count($images->image); $y++)
{
if($y == 0)
{
$xx = $xml->item[$i]->images->addChild('image', $images->image[$y]);
}else {
$xml->item[$i]->images->addChild('image' . $y, $images->image[$y]);
}
}
var_dump($images);
}
}
$xml->asXML('POTO.xml');
The dilemma I have tho is that none of the childs get added to images. I have been told I need to restructure the whole document but this is kind of silly if I var_dump just after removing the images node the node and it's children are all removed however when I go to add images node back to item node it and var_dump the node it shows the node was added to item node as a child however when I try to add image to images nothing gets added.
Do I really need to restructure the whole document because it seems simpler to do it in Java then. Or did I miss something.
Okay, I think the key problem here is that assigning the images to $images doesn't work like you'd expect. While such an assignment of a primitive makes a copy, assigning an object makes a reference to the same object (similar to a pointer you've worked with lower level languages). They do this because an object can be larger than a primitive, and unnecessary duplication of that is just wasteful.
However, in this case, the result is that when you unset the images from the main SimpleXML object, you're also destroying the instance in $images. Fortunately, there is a solution. You can clone the object, rather than assigning it. See http://www.php.net/manual/en/language.oop5.cloning.php
I modified your sample code here and it seems to work: http://3v4l.org/ZmRZV
Edit: cleaned up my code a little and included it:
<?php
//$xml = simplexml_load_file('data.xml');
$xml = simplexml_load_string('<items>
<item>
<images>
<image>A</image>
<image>B</image>
<image>C</image>
</images>
</item>
</items>');
// Loop over items in original xml
foreach ($xml->item as $item) {
if (count($item->images->image) > 1) {
// Clone entry
$images = clone $item->images;
// Remove entry and replace with empty
unset($item->images);
$item->addChild('images');
for ($i = 0; $i < count($images->image); $i++) {
$num = ($i > 0) ? $i : '';
$item->images->addChild('image'.$num, $images->image[$i]);
}
}
}
//$xml->asXML('POTO.xml');
echo $xml->asXML();
Looks like this doesn't work prior to version 5.2.1 (http://3v4l.org/m0VoD), but that's going back pretty far, really. Rasmus doesn't want anyone running less than 5.4 (http://www.youtube.com/watch?v=anr7DQnMMs0&t=10m27s), and I'm inclined to agree.
For the record, this behavior, of copying only the reference is not a quirk of PHP. It's a common practice. Further reading: http://en.wikipedia.org/wiki/Cloning_(programming)
I am trying to edit an XML document using PHP, but it does not seem to work, wonder where I am going wrong!
I am trying to do it the following way which I found online. Can anyone please show me the right direction?
XML
<gold>
<coin>
<id>1</id>
<title>Gold Coin 50 Grams</title>
<price>500 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
<coin>
<id>2</id>
<title>Gold Coin 50 Grams</title>
<price>500 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>
http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
...
</gold>
PHP Code
$xmlDoc = new DOMDocument();
$xmlDoc->loadXml($str);
$events = $xmlDoc->getElementsByTagName("coin");
foreach($events as $event){
$eventNames = $event->getElementsByTagName("price");
$eventN = $eventNames->item(0)->nodeValue;
if('500' == $eventN){ // ** Failed here, instead of '500',
// I used '500 rupees' and it worked, as that matches the original text.**
$eventNames->item(0)->nodeValue = $rest ;
}
}
var_dump($xmlDoc->saveXML());
Here's the desired result. Notice how I've changed the price tag to 2495 rupees.
<gold>
<coin>
<id>1</id>
<title>Gold Coin 50 Grams</title>
<price>2495 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
<coin>
<id>2</id>
<title>Gold Coin 50 Grams</title>
<price>2495 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>
http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
...
</gold>
Here's a quick solution based on SimpleXML:
$gold = new SimpleXMLElement($xml);
foreach ($gold->coin as $coin) {
$coin->price = str_replace('500', $rest, (string) $coin->price);
}
echo $gold->asXML();
Working demo.
Oh hey, it was a mistake on my part, the function works perfect, instead of
if('500' == $eventN)
The Correct woulld be
if('500 rupees' == $eventN)
Dumb