4

I am trying to understand how schema validation validates merged layout files in Magento 2. XSD schema called layout_merged.xsd is used to validate layout in the \Magento\Framework\Config\Dom::validateDomDocument() method. It seems error occurs in system.log file every time it is validated.

[2017-02-09 10:59:34] main.INFO: Cache file with merged layout: LAYOUT_frontend_STORE2_46f1b068ec7ccf4878f9284dd1137afd1 and handles catalog_product_prices: Please correct the XML data and try again. Warning: DOMDocument::schemaValidate(): Invalid Schema in vendor/magento/framework/Config/Dom.php on line 311 [] []

The merged file seems correct for example catalog_product_prices.xml, I saved content of the merged xml into the file and added xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_merged.xsd" to see how it validates in PHPStorm.

It shows that block, referenceContainer, arguments are not allowed node names in the xml. According to layout_merged.xsd these nodes are allowed.

I will appreciate if you could advice me if I am missing something.

Updated follow up information. Here is a one of merged layouts, let's call it "a collection of all catalog_product_prices.xml layout files":

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_merged.xsd">
<handle id="handle">
    <block class="Magento\Framework\Pricing\Render\RendererPool" name="render.product.prices">
        <arguments>
            <argument name="default" xsi:type="array">
                <item name="default_render_class" xsi:type="string">Magento\Catalog\Pricing\Render\PriceBox</item>
                <item name="default_render_template" xsi:type="string">Magento_Catalog::product/price/default.phtml</item>
           <item name="default_amount_render_class" xsi:type="string">Magento\Framework\Pricing\Render\Amount</item>
           <item name="default_amount_render_template" xsi:type="string">Magento_Catalog::product/price/amount/default.phtml</item>
           <item name="prices" xsi:type="array">
              <item name="special_price" xsi:type="array">
                 <item name="render_template" xsi:type="string">Magento_Catalog::product/price/special_price.phtml</item>
              </item>
              <item name="tier_price" xsi:type="array">
                 <item name="render_template" xsi:type="string">Magento_Catalog::product/price/tier_prices.phtml</item>
              </item>
              <item name="final_price" xsi:type="array">
                 <item name="render_class" xsi:type="string">Magento\Catalog\Pricing\Render\FinalPriceBox</item>
                 <item name="render_template" xsi:type="string">Magento_Catalog::product/price/final_price.phtml</item>
              </item>
              <item name="custom_option_price" xsi:type="array">
                 <item name="amount_render_template" xsi:type="string">Magento_Catalog::product/price/amount/default.phtml</item>
              </item>
              <item name="configured_price" xsi:type="array">
                 <item name="render_class" xsi:type="string">Magento\Catalog\Pricing\Render\ConfiguredPriceBox</item>
                 <item name="render_template" xsi:type="string">Magento_Catalog::product/price/configured_price.phtml</item>
              </item>
           </item>
        </argument>
     </arguments>
  </block>
  <referenceBlock name="render.product.prices">
     <arguments>
        <argument name="default" xsi:type="array">
           <item name="adjustments" xsi:type="array">
              <item name="default" xsi:type="array">
                 <item name="tax" xsi:type="array">
                    <item name="adjustment_render_class" xsi:type="string">Magento\Tax\Pricing\Render\Adjustment</item>
                    <item name="adjustment_render_template" xsi:type="string">Magento_Tax::pricing/adjustment.phtml</item>
                 </item>
              </item>
           </item>
        </argument>
        <argument name="bundle" xsi:type="array">
           <item name="adjustments" xsi:type="array">
              <item name="bundle_option" xsi:type="array">
                 <item name="tax" xsi:type="array">
                    <item name="adjustment_render_class" xsi:type="string">Magento\Tax\Pricing\Render\Adjustment</item>
                    <item name="adjustment_render_template" xsi:type="string">Magento_Tax::pricing/adjustment/bundle.phtml</item>
                 </item>
              </item>
           </item>
        </argument>
     </arguments>
  </referenceBlock>
  <referenceBlock name="render.product.prices">
     <arguments>
        <argument name="default" xsi:type="array">
           <item name="prices" xsi:type="array">
              <item name="wishlist_configured_price" xsi:type="array">
                 <item name="render_class" xsi:type="string">Magento\Wishlist\Pricing\Render\ConfiguredPriceBox</item>
                 <item name="render_template" xsi:type="string">Magento_Catalog::product/price/configured_price.phtml</item>
              </item>
           </item>
        </argument>
     </arguments>
  </referenceBlock>
</handle>
</layout>

I stored this layout during debug and included xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_merged.xsd"> into this file to see highlighted nodes which are not valid as per layout_merged.xsd definitions.

It shows block, arguments and referenceBlock as red in PHPStorm, meaning it is not valid. Here is a screenshot on how it looks like: merged layout file as a result of all catalog_product_prices.xml files

The vendor/magento/framework/View/Layout/etc/layout_merged.xsd file states that all mentioned nodes are allowed for use:

<xs:element name="handle" type="handleType">
    <xs:unique name="blockKey">
        <xs:selector xpath=".//block"/>
        <xs:field xpath="@name"/>
    </xs:unique>
    <xs:unique name="containerKey">
        <xs:selector xpath=".//container"/>
        <xs:field xpath="@name"/>
    </xs:unique>
    <xs:keyref name="blockReference" refer="blockKey">
        <xs:selector xpath=".//referenceBlock"/>
        <xs:field xpath="@name"/>
    </xs:keyref>
    <xs:keyref name="containerReference" refer="containerKey">
        <xs:selector xpath=".//referenceContainer"/>
        <xs:field xpath="@name"/>
    </xs:keyref>
</xs:element>

Since layout_merged.xsd file extends the vendor/magento/framework/View/Layout/etc/elements.xsd it also allows using attributes node.

So my questions are:

  1. Why result of merged layout catalog_product_prices.xml files highlights that nodes can't be used?
  2. If all separate layout files are correct and XSD validation is passed for all individual layout files, in this example catalog_product_pruces.xml. why result of merged layout is failing and we see main.INFO: Cache file with merged layout: ... records in the system.log file?

I assume layout_merged.xsd has bug it is not properly validating merged files.

  • 2
    Maybe that can help: magento.stackexchange.com/q/142503/2380 – Raphael at Digital Pianism Feb 9 '17 at 12:24
  • THanks @RaphaelatDigitalPianism. I've read everything on the link provided. Unfortunately it does not give me a clue of a "way" how and "why" i see errors in system.log file. – Max Pronko Feb 9 '17 at 12:39
  • Is there possibility that the merge itself produced wrong results? Are individual files valid by itself? Is this XML something yu can share? – Eugene Tulika Feb 9 '17 at 16:31
  • Hi @EugeneTulika, Individual files are correct, no issues with them, merged are always failing validation. Updated my question with details. – Max Pronko Feb 10 '17 at 10:33
  • @MaxPronko Could you help me with this magento.stackexchange.com/questions/174670/… – Mukesh May 16 '17 at 17:46
3

Followed next steps:

  • downloaded latest mainline from https://github.com/magento/magento2:develop
  • created the file with the XML provided in the example of merged file
  • added links to the schema in my IDE Everything worked well with no errors.

Then, repeated same steps, but downloaded latest for 2.1 branch of the mainline. As a result, there is the same error as it was reported.

My investigation of the issue in the git history shows that it was fixed as a part of the story on better XML validation and error processing for 2.2. A number of similar errors were fixed across other XSD files.

The issue with the 2.1 was reported back to Product Owners, backporting of the fixes from the mainline to 2.1 should be prioritized for one of the upcoming 2.1 patch releases.

| improve this answer | |
  • Do you have a GitHub link for the issue? – Alex Jul 11 '17 at 19:05
3

It's not 100% clear what you're asking -- but that might be because you don't have enough information to ask the right question. :)

When Magento 2.1.3 loads its layout files on a non-cached hit, after reading them from disk across every module and every theme, it ends up with a layout structure that looks like this

<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <handle id="[HANDLE ID]">
        <!-- ... nodes ... -->
    </handle>
</layout>

This is roughly equivalent to the "Package Layout" in Magento 1. I mentioned this briefly in my Magento 2: 10,000 ft. Layout Rendering View post.

The urn:magento:framework:View/Layout/etc/layout_merged.xsd schema is meant to validate these merged documents. It's not meant to validate stand-alone documents like catalog_product_price.xml. If you try to run a stand-alone file through layout_merged.xsd, you'll get complains about

block, referenceContainer arguments are not allowed node names in the xml

This isn't because these nodes are not allowed, it's because there's no surrounding <handle/> tag. Schemas not only say what nodes are allowed, but where they're allowed.

It's not clear from your question if you already did this or not, but I'd jump to here

#File: vendor/magento//framework/Config/Dom.php
try {
    $result = $dom->schemaValidate($schema);
    if (!$result) {
        $errors = self::getXmlErrors($errorFormat);
    }
} catch (\Exception $exception) {
    libxml_use_internal_errors(false);
    throw $exception;
}

and log the contents of the DomDocument object in $dom. This will be the merged XML that your system is complaining about, and the one you want to run through layout_merged.xsd. If there's problems with this file, it's because something went wrong when Magento was building the handle layout file. It's harder to be more specific than that with the information you've provided. One possible debugging technique would be to temporarily rename all the catalog_product_price.xml files in the system (including Magento's) and re-add them until the error reoccurs. (although it may be possible some PHP code is adding catalog_product_price handles programmatically)

Hope that helps and good luck!

| improve this answer | |
  • Thanks for the response. I updated my question with examples for your better understanding of a problem :). Thanks for help. – Max Pronko Feb 10 '17 at 10:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.