Magento 2 – Merged Layout Schema Validation Error

magento2

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.

Best Answer

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.

Related Topic