I have a very simple code with domDocumet, but it has a mistake I can't solve:
function getTagXML($mensaje, $tagname){
$dom = new domDocument('1.0', 'UTF-8');
libxml_use_internal_errors(true);
// load the html into the object ***/
$dom->loadHTML($mensaje);
//discard white space
$dom->preserveWhiteSpace = false;
$nodeList= $dom->getElementsByTagName($tagname); // here u use your desired tag
$node = $nodeList->item(0);
$item = trim($node->nodeValue);
libxml_clear_errors();
return $item;
}
I got the error:
Notice: Trying to get property of non-object in line 82:
The line 82:
$item = trim($node->nodeValue);
The error message means that $nodeList isn't an object, which means that $dom->getElementsByTagName($tagname) returned NULL.
Based on your other question I would assume that this happens because your XML document is malformed, that is it's missing a root node.
Related
I have the following source code:
<?php
function getTerms()
{
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML('https://charitablebookings.com/terms'); // loads your HTML
$xpath = new DOMXPath($doc);
// returns a list of all links with rel=nofollow
$nodeList = $xpath->query("//div[#class='terms-conditions']");
$temp_dom = new DOMDocument();
$node = $nodeList->item(0);
$temp_dom = new DOMDocument();
foreach($nodeList as $n) $temp_dom->appendChild($temp_dom->importNode($n,true));
print_r($temp_dom->saveHTML());
}
getTerms();
?>
which I'm trying to get a text from a web page by getting a specific class. I don't get anything on my browser when I try to print_r the temp_dom. And $node is null. What am I doing wrong ?
Thanks for your time
The first issue is that DOMDocument's loadHTML method expects HTML content as its first parameter, not an URL.
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$html = file_get_contents('https://charitablebookings.com/terms');
$doc->loadHTML($html);
And the second problem is with your XPath expression: $xpath->query("//div[#class='terms-conditions']") - as there is no div with class of terms-conditions in the document (it probably gets added by some JavaScript loader).
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);
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;
}
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)));
}
Creating the DOMDocument object:
$getToken = '<getToken>...</getToken>';
$getToken_objeto = new DOMDocument("1.0", "UTF-8");
$getToken_objeto -> loadXML($getToken);
Trying to append a XML string (Signature) into the DOMDocument created above:
$Signature = '<Signature>...</Signature>';
$Signature_objeto = new DOMDocument("1.0", "UTF-8");
$Signature_objeto -> loadXML($Signature);
$Signature_nodeList = $Signature_objeto -> getElementsByTagName("Signature");
$Signature_node = $Signature_nodeList -> item(0);
$getToken_objeto -> importNode($Signature_node, true);
$getToken_objeto -> appendChild($Signature_node);
I get 2 errors:
Fatal error: Uncaught exception 'DOMException' with message 'Wrong Document Error' in C:...
DOMException: Wrong Document Error in C:...
Seems simple to resolve but im quite unexperienced using the PHP DOM extension.
Thanks in advance.
You're trying to append the original node - not the imported one.
$Signature_node = $getToken_objeto->importNode(
$Signature_nodeList->item(0), true
);
You're trying to append the node to the document, but an XML document can only have a single document element and it already has one. You can append it to the document element:
$getToken_objeto->documentElement->appendChild($Signature_node);
But PHP can load XML fragments directly into a DOMDocumentFragment.
$xml = '<getToken>...</getToken>';
$fragmentXml = '<Signature>...</Signature>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXpath($dom);
$fragment = $dom->createDocumentFragment();
$fragment->appendXml($fragmentXml);
$xpath
->evaluate('//getToken')
->item(0)
->appendChild($fragment);
echo $dom->saveXml();