PHP DOMDocument: Fatal error: Call to undefined method DOMElement::save() - php

I'm trying to indent my XML file, but I can't because of this error.
Why is this problem appear?
This is my code:
<?php
$xmlstr = 'xmlfile.xml';
$sxe = new SimpleXMLElement($xmlstr, null, true);
$lastID = (int)$sxe->xpath("//tip[last()]/tipID")[0] + 1;
$tip = $sxe->addChild('tip');
$tip->addChild('tipID', $lastID);
$tip->addChild('tiptitle', 'Title:');
$sxe->asXML($xmlstr);
$xmlDom = dom_import_simplexml($sxe);
$xmlDom->formatOutput = true;
$xmlDom->save($xmlstr);
?>
I've done a lot of research and I couldn't find an answer.

DOMElement has not method to save xml, but DOMDocument does. Make DOMDocument before:
$xmlDom = dom_import_simplexml($sxe);
$dom = new DOMDocument();
$dom_sxe = $dom->importNode($xmlDom, true);
$dom_sxe = $dom->appendChild($xmlDom);
$Dom->formatOutput = true;
echo $dom->saveXML();

The dom_import_simplexml function returns an instance of DOMElement, which has no save method. What you need instead is a DOMDocument, which does have a save method.
Luckily, it's really easy to get from one to the other, because a DOMElement is a type of DOMNode, and so has an ownerDocument property. Note that the formatOutput attribute is also part of the DOMDocument, so what you need is this:
$xmlDom = dom_import_simplexml($sxe)->ownerDocument;
$xmlDom->formatOutput = true;
$xmlDom->save($xmlstr);

Related

Search within XML with PHP code

this is my code and i am trying to show the value of xml using Xpath but when i run this i am getting error in my code.
Here is the code
<?php
$load = new DOMDocument();
$load = simplexml_load_file("testing.xml");
var_dump($load);
$xpath = new DOMXpath($load);
var_dump($xpath);
$path1 = "/clip/metadata[name=keywords]/value";
$query = $xpath->query($path1);
var_dump("$query");
?>
this is the error, which i am getting
Catchable fatal error: Argument 1 passed to DOMXPath::__construct() must be an instance of DOMDocument, instance of SimpleXMLElement given in C:\xampp\htdocs\xml-text\index.php on line 5
As the error states, you are not passing the constructor the appropriate arguments. simplexml_load_file returns a SimpleXmlElement object, NOT a DOMDocument object.
As stated in the error, you are passing a SimpleXmlElement object instead of a DOMDocument object.
My previous answer was incorrect. It showed how to convert a SimpleXmlElement to a DOMElement not a DOMDocument.
http://php.net/manual/en/domdocument.load.php is how to properly load an xml file into a DOMDocument object.
$load = new DOMDocument();
$load->load("testing.xml");
$xpath = new DOMXpath($load);
Specifically to get the value of the node with the name Keywords you would do something like this
$load = new DOMDocument();
$load->preserveWhiteSpace = false;
$load->load(__DIR__ . "/testing.xml");
$xpath = new DOMXpath($load);
$path1 = '//clip/metadata/name[ . = "Keywords"]';
$query = $xpath->query($path1);
foreach($query as $entry) {
$value = $entry->parentNode->childNodes->item(1)->nodeValue;
}

domDocument's formatOutput property writes inline [duplicate]

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)));
}

Call to undefined method DOMElement::appendChid()

I generating xml.When i try to add cdata it gives me error
$dom = new DomDocument("1.0", "ISO-8859-1");
$root = $dom->appendChild($dom->createElement( "Questions"));
$sxe = simplexml_import_dom( $dom );
$question = $sxe->addchild("Question");
$question->addAttribute('id', $Question_Id);
$question->addAttribute('type', $type);
$question->appendChild($sxe->createCDATASection( $Questiontext));//error
$question->addChild('Option_One', $Option_One);
$dom->formatOutput = true;
$xmlString = $dom->saveXML();
print($xmlString);
$dom->save("{$Campaign_Name}.xml");
You have made a spelling mistake, instead of appendChild you write appendChid
$question->appendChild(new DOMElement('direction'))->appendChild(new DOMCdataSection('<p>Hello!</p>'));
for DOM

displaying Simple XML php

I am looking for something equivalent to this:
$e= xmlwriter_open_uri("test.xml");
....
print htmlentities(xmlwriter_output_memory($e));
now this print allows to display whats in the xml list into a table.
But my with my simple xml (combined with $dom for formatting) i have no idea how to display this. Although this generates the proper output i wish into the xml how do i display the xml below? Something similar to a print or?
The purpose is to display the values of the xml into a table.
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$xml = new SimpleXMLElement('<test></test>');
$one= $xml->addChild('enemy', 'yes');
$two= $xml->addChild('friend', 'maybe');
$dom->loadXML($xml->asXML());
$dom->save('test.xml');
Regards
You don't need to stringify (technical term!) the SimpleXMLElement to load it into a DOMDocument, in fact that's a terrible idea (though, you're forgiven).
$xml = new SimpleXMLElement('<test></test>');
$one= $xml->addChild('enemy', 'yes');
$two= $xml->addChild('friend', 'maybe');
// Get the DOMDocument associated with this XML
$dom = dom_import_simplexml($xml)->ownerDocument;
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
echo $dom->saveXML(); // or echo htmlentities($dom->saveXML()) if you really must
More info about retrieving a DOMElement (and its DOMDocument) from a SimpleXMLElement can be found in the docs for dom_import_simplexml().

Call to a member function xpath() on a non-object?

I'm trying to grab an image from a web site using simpleXML and am getting a PHP error saying that I'm trying to call to a member function xpath() on a non-object.
Below are the lines I'm trying to use to get the image's source tag:
$xpath = '/html/body/div/div/div[5]/div/div/div[2]/div/div[2]/img';
$html = new DOMDocument();
#$html->loadHTMLFile($target_URL);
$xml = simplexml_import_dom($html);
$source_image = $xml->xpath($xpath);
$source_image = $source_image[0]['src'];
What am I doing wrong? It's pretty clear the second to last line has a problem, but I'm not sure what it is.
Try this code to first make sure that the document is being parsed correctly.
$xpath = '/html/body/div/div/div[5]/div/div/div[2]/div/div[2]/img';
$html = new DOMDocument();
#$html->loadHTMLFile($target_URL);
$xml = simplexml_import_dom($html);
if (!$xml) {
echo 'Error while parsing the document';
exit;
}
$source_image = $xml->xpath($xpath);
$source_image = $source_image[0]['src'];
Problem solved. Was funning xpath on an empty string.

Categories