How to easily Debug Layout Xml Warning/Error?

11,755

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.

Share:
11,755
WonderLand
Author by

WonderLand

Updated on June 20, 2022

Comments

  • WonderLand
    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, '&lt;' 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
    WonderLand over 11 years
    Your 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
    Roman Snitko over 11 years
    There is nothing special related to Magento architecture, it is just XML file :)
  • WonderLand
    WonderLand over 11 years
    Are 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
    Roman Snitko over 11 years
    Of 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
    WonderLand over 11 years
    ok can you add precise instruction ? I should add some code some where ?
  • WonderLand
    WonderLand over 11 years
    thank you this is a part of the solution, I can figure out the module name but not the current file processed
  • Roman Snitko
    Roman Snitko over 11 years
    In debug trace you should see everything. Take a look at Varien_Simplexml_Config->loadFile() - there is variable $filePath.
  • WonderLand
    WonderLand over 11 years
    Thank you I have edited you answer in order to make it more general and Xdebug independent ( and also get filename )
  • phagento
    phagento over 10 years
    I'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