I'm trying to import one node from one document to another. This throws an 'Wrong Document Error' error:
$xml = <<<XML
<root>
<child1>foo </child1>
<child2> bar</child2>
</root>
XML;
$doc = new DOMDocument;
$new = new DOMDocument;
$doc->loadXML($xml);
$xp = new DOMXPath($doc);
foreach($xp->query('/root/node()') as $element)
{
$new->appendChild($doc->importNode($element, true));
}
echo $new->saveXML();
You want to use $new->importNode... rather than $doc->importNode... as $new is the document you're trying to add the node to.
Here are the codes:
$doc = new DomDocument('1.0');
// create root node
$root = $doc->createElement('root');
$root = $doc->appendChild($root);
$signed_values = array('a' => 'eee', 'b' => 'sd', 'c' => 'df');
// process one row at a time
foreach ($signed_values as $key => $val) {
// add node for each row
$occ = $doc->createElement('error');
$occ = $root->appendChild($occ);
// add a child node for each field
foreach ($signed_values as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
}
}
// get completed xml document
$xml_string = $doc->saveXML() ;
echo $xml_string;
If I print it in the browser I don't get nice XML structure like
<xml> \n tab <child> etc.
I just get
<xml><child>ee</child></xml>
And I want to be utf-8
How is this all possible to do?
You can try to do this:
...
// get completed xml document
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$xml_string = $doc->saveXML();
echo $xml_string;
You can make set these parameter right after you've created the DOMDocument as well:
$doc = new DomDocument('1.0');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
That's probably more concise. Output in both cases is (Demo):
<?xml version="1.0"?>
<root>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
<error>
<a>eee</a>
<b>sd</b>
<c>df</c>
</error>
</root>
I'm not aware how to change the indentation character(s) with DOMDocument. You could post-process the XML with a line-by-line regular-expression based replacing (e.g. with preg_replace):
$xml_string = preg_replace('/(?:^|\G) /um', "\t", $xml_string);
Alternatively, there is the tidy extension with tidy_repair_string which can pretty print XML data as well. It's possible to specify indentation levels with it, however tidy will never output tabs.
tidy_repair_string($xml_string, ['input-xml'=> 1, 'indent' => 1, 'wrap' => 0]);
With a SimpleXml object, you can simply
$domxml = new DOMDocument('1.0');
$domxml->preserveWhiteSpace = false;
$domxml->formatOutput = true;
/* #var $xml SimpleXMLElement */
$domxml->loadXML($xml->asXML());
$domxml->save($newfile);
$xml is your simplexml object
So then you simpleXml can be saved as a new file specified by $newfile
<?php
$xml = $argv[1];
$dom = new DOMDocument();
// Initial block (must before load xml string)
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// End initial block
$dom->loadXML($xml);
$out = $dom->saveXML();
print_R($out);
Tried all the answers but none worked. Maybe it's because I'm appending and removing childs before saving the XML.
After a lot of googling found this comment in the php documentation. I only had to reload the resulting XML to make it work.
$outXML = $xml->saveXML();
$xml = new DOMDocument();
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
$xml->loadXML($outXML);
$outXML = $xml->saveXML();
// ##### IN SUMMARY #####
$xmlFilepath = 'test.xml';
echoFormattedXML($xmlFilepath);
/*
* echo xml in source format
*/
function echoFormattedXML($xmlFilepath) {
header('Content-Type: text/xml'); // to show source, not execute the xml
echo formatXML($xmlFilepath); // format the xml to make it readable
} // echoFormattedXML
/*
* format xml so it can be easily read but will use more disk space
*/
function formatXML($xmlFilepath) {
$loadxml = simplexml_load_file($xmlFilepath);
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($loadxml->asXML());
$formatxml = new SimpleXMLElement($dom->saveXML());
//$formatxml->saveXML("testF.xml"); // save as file
return $formatxml->saveXML();
} // formatXML
Two different issues here:
Set the formatOutput and preserveWhiteSpace attributes to TRUE to generate formatted XML:
$doc->formatOutput = TRUE;
$doc->preserveWhiteSpace = TRUE;
Many web browsers (namely Internet Explorer and Firefox) format XML when they display it. Use either the View Source feature or a regular text editor to inspect the output.
See also xmlEncoding and encoding.
This is a slight variation of the above theme but I'm putting here in case others hit this and cannot make sense of it ...as I did.
When using saveXML(), preserveWhiteSpace in the target DOMdocument does not apply to imported nodes (as at PHP 5.6).
Consider the following code:
$dom = new DOMDocument(); //create a document
$dom->preserveWhiteSpace = false; //disable whitespace preservation
$dom->formatOutput = true; //pretty print output
$documentElement = $dom->createElement("Entry"); //create a node
$dom->appendChild ($documentElement); //append it
$message = new DOMDocument(); //create another document
$message->loadXML($messageXMLtext); //populate the new document from XML text
$node=$dom->importNode($message->documentElement,true); //import the new document content to a new node in the original document
$documentElement->appendChild($node); //append the new node to the document Element
$dom->saveXML($dom->documentElement); //print the original document
In this context, the $dom->saveXML(); statement will NOT pretty print the content imported from $message, but content originally in $dom will be pretty printed.
In order to achieve pretty printing for the entire $dom document, the line:
$message->preserveWhiteSpace = false;
must be included after the $message = new DOMDocument(); line - ie. the document/s from which the nodes are imported must also have preserveWhiteSpace = false.
based on the answer by #heavenevil
This function pretty prints using the browser
function prettyPrintXmlToBrowser(SimpleXMLElement $xml)
{
$domXml = new DOMDocument('1.0');
$domXml->preserveWhiteSpace = false;
$domXml->formatOutput = true;
$domXml->loadXML($xml->asXML());
$xmlString = $domXml->saveXML();
echo nl2br(str_replace(' ', ' ', htmlspecialchars($xmlString)));
}
I have a little question ... this is my xml:
<?xml version="1.0" encoding="UTF-8"?>
<links>
<link>
<id>432423</id>
<href>http://www.google.ro</href>
</link>
<link>
<id>5432345</id>
<href>http://www.youtube.com</href>
</link>
<link>
<id>5443</id>
<href>http://www.yoursite.com</href>
</link>
</links>
How can i ad another
<link>
<id>5443</id>
<href>http://www.yoursite.com</href>
</link>
??
I managed only to add a record to ROOT/LINKS -> LINK using xpath, and here is the code
<?php
$doc = new DOMDocument();
$doc->load( 'links.xml' );
$links= $doc->getElementsByTagName("links");
$xpath = new DOMXPath($doc);
$hrefs = $xpath->evaluate("/links");
$href = $hrefs->item(0);
$item = $doc->createElement("item");
/*HERE IS THE ISSUE...*/
$link = $doc->createElement("id","298312800");
$href->appendChild($link);
$link = $doc->createElement("link","www.anysite.com");
$href->appendChild($link);
$href->appendChild($item);
print $doc->save('links.xml');
echo "the link has been added!";
?>
Any help would be appreciated :D
$doc = new DOMDocument();
// Setting formatOutput to true will turn on xml formating so it looks nicely
// however if you load an already made xml you need to strip blank nodes if you want this to work
$doc->load('links.xml', LIBXML_NOBLANKS);
$doc->formatOutput = true;
// Get the root element "links"
$root = $doc->documentElement;
// Create new link element
$link = $doc->createElement("link");
// Create and add id to new link element
$id = $doc->createElement("id","298312800");
$link->appendChild($id);
// Create and add href to new link element
$href = $doc->createElement("href","www.anysite.com");
$link->appendChild($href);
// Append new link to root element
$root->appendChild($link);
print $doc->save('links.xml');
echo "the link has been added!";
XPath is used to locate nodes in an XML document, not to manipulate the tree. Try $dom->appendChild($new_link).
I'm processing a XML with XSL with PHP to a HTML output. So far, so good. Here's my code.
<?php
$xslDoc = new DOMDocument();
$xslDoc->load("content.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("content.xml");
// some xpath/dom-query filtering to get
// subtree of loaded xml-file
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDoc);
?>
Like you can see, this is a simple XSLT Processor. The output works well. For example I have in the given XML three sibling nodes "node":
<root>
<node>
<subnode>..</subnode>
</node>
<node>
<subnode>..</subnode>
</node>
<node>
<subnode>..</subnode>
</node>
</root>
Now I want just pass the second node through the XML Processor.
How can I do this?
chris
According to http://www.php.net/manual/en/xsltprocessor.transformtodoc.php, the transformToDoc method takes any DOM node as its argument so you could access $xmlDoc->getElementsByTagName('node')->item(1) and pass that to transformToDoc and then use saveXML or saveHTML to get a string of XML or HTML, depending on what kind of result you are looking for.
I solved my task by my own - but thank you for your application.
Here is my code:
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->load("content.xml");
$xpath = new DOMXPath($xmlDoc);
$query = '//ContentData/Content[1]/Headline';
$nodeList = $xpath->query($query);
$newDom = new DOMDocument('1.0','UTF-8');
$root = $newDom->createElement('root');
$root = $newDom->appendChild($root);
foreach ($nodeList as $domElement){
$domNode = $newDom->importNode($domElement, true);
$root->appendChild($domNode);
}
$newDom->saveXML();
$xslDoc = new DOMDocument();
$xslDoc->load("content.xsl");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($newDom);
from this xml file i want to delete picture node according to attribute id.
i have written php code but it does not work.
<gallery>
<organizate>
<organization w="3" h="1" space="17"/>
<organization w="4" h="2" space="17"/>
<organization w="6" h="3" space="7"/>
</organizate>
<pictures>
<picture target="events/preview/10picture1.jpg" title="test1" movie="" text="test1" link="events_calender.php" id="38"/>
<picture target="events/preview/8picture7.jpg" title="test2" movie="" text="cxvxc" link="events_calender.php" id="39"/>
<picture target="events/preview/5picture10.jpg" title="test3" movie="" text="test3" link="events_calender.php" id="40"/>
</pictures>
</gallery>
PHP code
$doc = new DOMDocument();
$doc->formatOutput = TRUE;
$doc->preserveWhiteSpace = FALSE;
$xPath = new DOMXPath($doc);
$doc->load('../Event_gallery.xml');
$query = sprintf('//pictures[./picture[#id="%s"]]', 38);
foreach ($xPath->query($query) as $node) {
$node->parentNode->removeChild($node);
}
$doc->save('../Event_gallery.xml');
I think xpath is not working properly. control is not going in foreach
The problem is you are loading the document after you pass the document to DOMXPath.
Change
$xPath = new DOMXPath($doc);
$doc->load('../Event_gallery.xml');
to
$doc->load('../Event_gallery.xml');
$xPath = new DOMXPath($doc);
Then it should work.
To remove just the picture element with the given id instead of the whole parent, change the XPath to
//pictures/picture[#id="38"]