I need to create a new XML file and write that to my server. So, I am looking for the best way to create a new XML file, write some base nodes to it, save it. Then open it again and write more data.
I have been using file_put_contents() to save the file. But, to create a new one and write some base nodes I am not sure of the best method.
Ideas?
DOMDocument is a great choice. It's a module specifically designed for creating and manipulating XML documents. You can create a document from scratch, or open existing documents (or strings) and navigate and modify their structures.
$xml = new DOMDocument();
$xml_album = $xml->createElement("Album");
$xml_track = $xml->createElement("Track");
$xml_album->appendChild( $xml_track );
$xml->appendChild( $xml_album );
$xml->save("/tmp/test.xml");
To re-open and write:
$xml = new DOMDocument();
$xml->load('/tmp/test.xml');
$nodes = $xml->getElementsByTagName('Album') ;
if ($nodes->length > 0) {
//insert some stuff using appendChild()
}
//re-save
$xml->save("/tmp/test.xml");
PHP has several libraries for XML Manipulation.
The Document Object Model (DOM) approach (which is a W3C standard and should be familiar if you've used it in other environments such as a Web Browser or Java, etc). Allows you to create documents as follows
<?php
$doc = new DOMDocument( );
$ele = $doc->createElement( 'Root' );
$ele->nodeValue = 'Hello XML World';
$doc->appendChild( $ele );
$doc->save('MyXmlFile.xml');
?>
Even if you haven't come across the DOM before, it's worth investing some time in it as the model is used in many languages/environments.
With FluidXML you can generate and store an XML document very easily.
$doc = fluidxml();
$doc->add('Album', true)
->add('Track', 'Track Title');
$doc->save('album.xml');
Loading a document from a file is equally simple.
$doc = fluidify('album.xml');
$doc->query('//Track')
->attr('id', 123);
https://github.com/servo-php/fluidxml
Related
I have a script that reads XML node by node using XMLReader:
$z = new XMLReader;
$z->open('xmlfile.xml');
$doc = new DOMDocument;
while ($z->read() && $z->name !== 'item');
while ($z->name === 'item')
{
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
//I read the node here
print_r($node);
//Here I want to delete it
//////////////////////////
//move to next node
$z->next('item');
}
I want to delete the node from XML file after reading it to avoid reading same data multiple times when calling the script again. What is the best way to do it? Am I able to do it while reading the file?
I couldn't find the answer anywhere else.
XMLReader has a partner called XMLWriter. So for large XML files you read the XML file using XMLReader while writing the filtered/modified data using XMLWriter into a new file.
Expanding a part of the file into DOM allows easier reading and modifications of this part but you will need to use XMLWriter to serialize the XML structure into the new file.
I implemented features (including a collapse() method) for that into FluentDOM. Here is an usage example:
$xml = <<<'XML'
<persons>
<person><name>Alice</name></person>
<person><name>Bob</name></person>
<person><name>Charlie</name></person>
</persons>
XML;
// Create the target writer and add the root element
$writer = new \FluentDOM\XMLWriter();
$writer->openUri('php://stdout');
$writer->setIndent(2);
$writer->startDocument();
$writer->startElement('persons');
// load the source into a reader
$reader = new \FluentDOM\XMLReader();
$reader->open('data://text/plain;base64,'.base64_encode($xml));
// iterate the person elements - the iterator expands them into a DOM element node
foreach (new \FluentDOM\XMLReader\SiblingIterator($reader, 'person') as $person) {
/** #var \FluentDOM\DOM\Element $person */
// ignore "Bob"
if ($person('string(name)') !== 'Bob') {
// write expanded node to the output
$writer->collapse($person);
}
}
$writer->endElement();
$writer->endDocument();
Output:
<?xml version="1.0"?>
<persons>
<person>
<name>Alice</name>
</person>
<person>
<name>Charlie</name>
</person>
</persons>
You can't edit the document while reading it .. at least not without a lot of messy inefficient code.
Best approach would be:
1) Read the entire document into a second DOMDocument object.
2) As you read nodes one by one from your XMLReader input stream, find the corresponding nodes in the DOMDocument and remove them after you are done. Be careful not to delete nodes that have children you have not yet reviewed.
3) When done save the new DomDocument to a new file name and use this as your input source for next edit session.
You will be an expert on DomDocument manipulation when you are done.
Post a new question if you run into problems.
I have the following XML file:-
http://services.jupix.co.uk/api/get_properties.php?clientID=553a6644a7dc21df315c90e0140ad60d&passphrase=324dd464aa7ba96ad0e8ab6d8f423162
What I need to do is fetch this data and split it into two different PHP files.
Within <property> you will see:-
<department>Sales</department>
and
<department>Lettings</department>
These are the fields I need it splitting by.
Any idea how I can do this?
With DOMDocument and XPath:
$dom = new DOMDocument;
$dom->load($url);
$xpath = new DOMXPath($dom);
$properties = $xpath->evaluate('/properties/property[not(department="Sales")]');
foreach ($properties as $property) {
$property->parentNode->removeChild($property);
}
echo $dom->save('Sales.xml');
This will load the XML from the remote URL into a DOMDocument and remove all property items from properties that do not contain an element where department is "Sales". Then it saves the resulting document to the file sales.xml.
For Lettings, you just adapt the XPath and save file to say Lettings instead of Sales.
You can also do this with SimpleXml or XmlReader+XmlWriter or an XSL transformation easily. I will leave that for others to post though.
I am beginner in PHP, XSLT. Found solution for transform XML using XSLT:
$xml = Array2XML::createXML('Document', $result);
$xsl = new DOMDocument;
$xsl->load('Teema.xsl');
$processor = new XSLTProcessor();
$processor->importStyleSheet($xsl);
$results=$processor->transformToXML($xml);
$results=$processor->transformToUri($xml,"NewTeema.xml" );
But, what to do if I have 2 or more XMLs?
This $xml is not file, and I dont want to save each xml, like file on server (because it is was converted response json). Any ideas?
In the XSLT you can load additional document using the document() function.
Another possibility is to register a PHP function that loads the file and returns the value or DOM node.
Good solution, but I decided to merge 2 json, like this:
json_encode(array_merge(json_decode($result,
true),json_decode($resultProducts, true)));
And the use = Array2XML::createXML('Document', $result);
I have a php file, with xml headers, that i wish my script to load.
$doc = new DOMDocument();
$doc->load( 'xmlscript.php' );
Will not work, only files with *.xml. How can i make it load the file, like it is a xml file?
Since it's the data from db, that it shows in xml format, the file is in .php.
You'll have to get the output from the PHP file, and parse that.
ob_start();
include 'xmlscript.php';
$result = ob_get_clean();
$doc = new DOMDocument();
$doc -> loadXml($result);
Something like that may help.
I have two different XML structured documents, an XSLT that renames the elements and nodes of them to satisfy both and a PHP code that will save them into a new XML doc.
This is the code I used for testing purposes, however how can I load two or more paths like book1.xml and book2.xml into the $xml ? I know how to $dom->load( 'book1.xml' );
<?php
// create an XSLT processor and load the stylesheet as a DOM
$xproc = new XsltProcessor();
$xslt = new DomDocument;
$xslt->load('stylesheet.xslt'); // this contains the code from above
$xproc->importStylesheet($xslt);
// your DOM or the source XML (copied from your question)
$xml = '';
$dom = new DomDocument;
$dom->loadXML($xml);
?>
Read about and use the standard XSLT function document().
In XSLT 2.0 there is also standard support for producing multiple result documents -- read about the <xsl:result-document> element.
If you are bound to XSLT 1.0, you cannot produce more than one result document in one transformation. You can either use extension libraries (EXSLT, the <exsl:document> extension element) or you can produce all results in one result document and then produce every single result out of it using another transformation, that you run once for producing each result.