DOMDocument - get node XML without adding namespaces - php

Test XML:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<testroot xmlns:abc="http://abc">
<testA>testNodeText</testA>
</testroot>
Test code:
$xml = file_get_contents('test.xml');
$dom = new \DOMDocument();
$dom->loadXML($xml);
var_dump(
$dom->C14N(),
$dom->getElementsByTagName('testA')->item(0)->C14N()
);
Result:
// 1
<testroot xmlns:abc="http://abc">\n
<testA>testNodeText</testA>\n
</testroot>
// 2
<testA xmlns:abc="http://abc">testNodeText</testA>
When getting content of node DOMDocument is adding namespace. Problem is that testA node is not equal to same testA node. This has huge impact when creating hash value from parts of XML.
I just can't get node from XML and calculate hash from it, because there are namespaces moved from document root.
Any ideas how I can get node content from DOMDocument to get it as it is in original document?

Related

Delete node from XML file while reading it with XmlReader?

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.

Multiple XML to DOM

I have multiple XML feeds with the same scheme and want to combine them to one bundle. I currently save 1 file like this:
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->load( 'http://FEEDURL.COM/FEED.PHP' );
$dom->encoding='UTF-8';
$dom->save( 'data.xml' ); /* <?xml version="1.0" encoding="UTF-8"?> */
I need this script to load multiple feeds and all save them to the one file called data.xml.
Use importNode in DOM.
http://php.net/manual/en/domdocument.importnode.php

How to append to a XML file with PHP preferably with SimpleXML

I have a XML file which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<data>
<config>
</config>
<galleries>
// We have loads of these <gallery>
<gallery>
<name>Name_Here</name>
<filepath>filepath/file.txt</filepath>
<thumb>filepath/thumb.png</thumb>
</gallery>
</galleries>
</data>
I have been trying to figure out how to append another < gallery > to my above xml file. I tried using simplexml but couldn't get it to work, so I tried this answer as well as a bunch of others on stackoverflow. But just cant get it to work.
I can read from a xml file easily and get all the info I need, But I need to be able to append a gallery tag to it, The code below doesnt work and when it does, I can only insert 1 element, and it inserts it 3 times, i dont understand this.
$data = 'xml/config.xml';
// Load document
$xml = new DOMDocument;
$xml->load( $data ); #load data into the element
$xpath = new DOMXPath($xml);
$results = $xpath->query('/data/galleries');
$gallery_node = $results->item(0);
$name_node = $xml->createElement('name');
$name_text = $xml->createTextNode('nametext');
$name_node = $name_node->appendChild($name_text);
$gallery_node->appendChild($name_node);
echo $xml->save($data);
I've had loads of failed attempts at this, this should be so easy. Basically I want to add a gallery with childs name filepath and thumb to this same file (xml/config.php).
Like I said, I kinda got it to work, but its unformatted and a doesnt have the gallery tag.
Question
How do I insert another < gallery > (with children) into the above XML file?
Preferably even using simpleXML
With SimpleXML, you can use the addChild() method.
$file = 'xml/config.xml';
$xml = simplexml_load_file($file);
$galleries = $xml->galleries;
$gallery = $galleries->addChild('gallery');
$gallery->addChild('name', 'a gallery');
$gallery->addChild('filepath', 'path/to/gallery');
$gallery->addChild('thumb', 'mythumb.jpg');
$xml->asXML($file);
Be aware that SimpleXML will not "format" the XML for you, however going from an unformatted SimpleXML representation to neatly indented XML is not a complicated step and is covered in lots of questions here.

How can I load multiple XML documents inside my PHP, DOM script?

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.

loading XML string into Xslt sheet

I am trying to load a xml document I created using PHP and DOM into a xslt sheet, but having no luck.
$xml_string = $doc->saveXML();
//echo $xml_string;
$xml = new DOMDocument;
$xml->load($xml_string);
$xsl = new DOMDocument;
$xsl->load('musicInformation.xslt');
// Configure the transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); // attach the xsl rules
echo $proc->transformToXML($xml);
I created a xml file based off some data extracted from a database and instead of saving it as an actual document I saved it as a string, I put the string into the xslt sheet and this error occurred
Warning: I/O warning : failed to load
external entity Warning: xpath.c:11079
Internal error: document without root
in
/home/dd615/public_html/webservice.php
on line 73
Any help would be much appreciated.
A string is not XML.
Valid XML needs a root element (that is, a single element that wraps all other elements in the document, apart from the XML declaration).
Such as this:
<?xml version="1.0" ?>
<root>
<element></element>
<element></element>
...
</root>
If you have multiple such roots, the XML is not valid and will fail to load.

Categories