How to easily Debug Layout Xml Warning/Error?
Solution 1
I think you can take a look at this article Dealing with XML errors.
This warning is related to some config.xml error, so a possible workaround to find out the exact file is to mod. the /lib/Varien/Simplexml/Config.php class.
You should modify Varien_Simplexml_Config::loadString()
method:
public function loadString($string)
{
if (is_string($string)) {
// Enable internal errors
libxml_use_internal_errors(true);
$xml = simplexml_load_string($string, $this->_elementClass);
if (false === $xml) {
// Put breakpoint here
$errors = libxml_get_errors();
}
if ($xml instanceof Varien_Simplexml_Element) {
$this->_xml = $xml;
return true;
}
} else {
Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
}
return false;
}
In case the error is related to some Layout file ( Update.php line 444 warning )
You should modify Mage_Core_Model_Layout_Update::getFileLayoutUpdatesXml()
method in a similar way:
public function getFileLayoutUpdatesXml($area, $package, $theme, $storeId = null)
{
if (null === $storeId) {
$storeId = Mage::app()->getStore()->getId();
}
/* @var $design Mage_Core_Model_Design_Package */
$design = Mage::getSingleton('core/design_package');
$layoutXml = null;
$elementClass = $this->getElementClass();
$updatesRoot = Mage::app()->getConfig()->getNode($area.'/layout/updates');
Mage::dispatchEvent('core_layout_update_updates_get_after', array('updates' => $updatesRoot));
$updateFiles = array();
foreach ($updatesRoot->children() as $updateNode) {
if ($updateNode->file) {
$module = $updateNode->getAttribute('module');
if ($module && Mage::getStoreConfigFlag('advanced/modules_disable_output/' . $module, $storeId)) {
continue;
}
$updateFiles[] = (string)$updateNode->file;
}
}
// custom local layout updates file - load always last
$updateFiles[] = 'local.xml';
$layoutStr = '';
foreach ($updateFiles as $file) {
$filename = $design->getLayoutFilename($file, array(
'_area' => $area,
'_package' => $package,
'_theme' => $theme
));
if (!is_readable($filename)) {
continue;
}
$fileStr = file_get_contents($filename);
$fileStr = str_replace($this->_subst['from'], $this->_subst['to'], $fileStr);
libxml_use_internal_errors(true);
$fileXml = simplexml_load_string($fileStr, $elementClass);
if (false === $fileXml) {
// Put breakpoint here
$errors = libxml_get_errors();
$err = array($filename, $errors);
// error detail and file name will be printed
Zend_Debug::dump($err);
die();
}
if (!$fileXml instanceof SimpleXMLElement) {
continue;
}
$layoutStr .= $fileXml->innerXml();
}
$layoutXml = simplexml_load_string('<layouts>'.$layoutStr.'</layouts>', $elementClass);
return $layoutXml;
}
Now just reload the page a read the error info.
Solution 2
Well, after a good search, if the $string
is all the CML merged, you have almost not chance to find what tag is bad closed.
I found a way to do it, in the class /lib/Varien/Simplexml/Config.php you have to modify the next method:
public function loadFile($filePath)
{
if (!is_readable($filePath)) {
//throw new Exception('Can not read xml file '.$filePath);
return false;
}
$fileData = file_get_contents($filePath);
$fileData = $this->processFileData($fileData);
//add this try catch
try{
$this->loadString($fileData, $this->_elementClass);
} catch (Exception $e) {
var_dump("The error: " . $e->getMessage());
var_dump("The bad file" . $filePath);
}
return $this->loadString($fileData, $this->_elementClass);
}
In this way we now can see what file has a bad tag.
Solution 3
If your test environment is Linux, you can also use XMLLint xmllint
to check the layout xml file for inconsistencies after you've made changes to it. Checking before implementation discovers a multitude of sins and prevents having errors thrown.
Solution 4
Edit file app/code/core/Mage/Core/Model/Layout/Update.php and search for function "getFileLayoutUpdatesXml".
Add:
Mage::log(print_r($filename, true));
aproximately at line 442, before:
$fileStr = file_get_contents($filename);
Solution 5
To resolve that case, in same file */lib/Varien/Simplexml/Config.php on line#489
Print path of loaded XML file put Zend_Debug::dump($filePath);
after $fileData = $this->processFileData($fileData);
and overwrite function loadString($string)
if (is_string($string)) {
$xml = simplexml_load_string($string, $this->_elementClass);
if ($xml instanceof Varien_Simplexml_Element) {
$this->_xml = $xml;
return true;
}
} else {
Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
}
return false;
Replace with
if (is_string($string)) {
// Enable internal errors
//Mage::log($string);
libxml_use_internal_errors(true);
$xml = simplexml_load_string($string, $this->_elementClass);
if (false === $xml) {
// Put breakpoint here
$errors = libxml_get_errors();
$err = array($errors);
// error detail and file name will be printed
Zend_Debug::dump($string);;
Zend_Debug::dump($err);
die();
}
if ($xml instanceof Varien_Simplexml_Element) {
$this->_xml = $xml;
return true;
}
} else {
Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
}
return false;
And this will print the path and error where this create problem.
WonderLand
Updated on June 20, 2022Comments
-
WonderLand almost 2 years
I got stuck on this error:
Warning: simplexml_load_string(): Entity: line 46: parser error : Comment not terminated in */lib/Varien/Simplexml/Config.php on line 510
and
Entity: line 46: parser error : Start tag expected, '<' not found in */lib/Varien/Simplexml/Config.php on line 510
It is clear that there is an issue in some Xml file, but really not easy for me to find out the needle in the big haystack :)
Any good practice for that? If possible I would like to find a good practice that involves use Xdebug, or some log.
It happens a lot of time in Magento to do some miss spelling.
-
WonderLand over 11 yearsYour solution is the one I always use I can say it is not very efficient: the problem is that magento load a lot of xml and so the debug line will triggered thousand of times ... I have tried adding a
try{} catch{}
but because it is a warning ... -
Roman Snitko over 11 yearsThere is nothing special related to Magento architecture, it is just XML file :)
-
WonderLand over 11 yearsAre you aware of how many xml are there in magento and how many times this line of code is triggered every time you load a page ?
-
Roman Snitko over 11 yearsOf course I know this. But those approach will take into account xml strings with errors only. You should make a call to
libxml_get_errors()
only if there is a problem with xml string loading. -
WonderLand over 11 yearsok can you add precise instruction ? I should add some code some where ?
-
WonderLand over 11 yearsthank you this is a part of the solution, I can figure out the module name but not the current file processed
-
Roman Snitko over 11 yearsIn debug trace you should see everything. Take a look at
Varien_Simplexml_Config->loadFile()
- there is variable $filePath. -
WonderLand over 11 yearsThank you I have edited you answer in order to make it more general and Xdebug independent ( and also get filename )
-
phagento over 10 yearsI've tried this several times. And it's very effective in fixing XML issues in Magento. This is the command you will use in the terminal
for file in
find . -name "*.xml"; do xmllint --noout $file; done