xmlxml-namespacesxsd-validationxinclude

XML XInclude looses namespace in included nodes


I'm trying to use namespaces on a xml file composed by more files.

XML Schema

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema
    version="1.0"
    attributeFormDefault="unqualified"
    elementFormDefault="qualified"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="urn:mynamespace"
    targetNamespace="urn:mynamespace">

    <xsd:element name="main_element" type="typeMainElement" />

    <xsd:complexType name="typeMainElement">
        <xsd:sequence>
            <xsd:element name="inner_element" type="typeInnerElement" />
        </xsd:sequence>
    <xsd:attribute name="test_attribute" type="xsd:string" use="required" />
    </xsd:complexType>

    <xsd:complexType name="typeInnerElement">
        <xsd:sequence>
            <xsd:element name="description" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

Main XML

<main_element test_attribute="value"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns="urn:mynamespace">
    <inner_element>
        <description>Test</description>
    </inner_element>
</main_element>

Validating the XML with the XML Schema works perfectly. But if I try to outsource some part of the XML, relying on XInclude then nothing works anymore.

Splitted XML

<main_element test_attribute="value"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns="urn:mynamespace">
    <xi:include href="simple_part.xml" />
</main_element>

Included XML

<inner_element>
    <description>Test</description>
</inner_element>

Trying to validate the Splitted XML returns the error:

simple_part.xml:1: element inner_element: Schemas validity error : Element 'inner_element': This element is not expected. Expected is ( {urn:mynamespace}inner_element ).

simple_main_element.xml fails to validate

It seems that when including I loose the namespace inheriting, so the included content doesn't have a namespace anymore.

-- How do I solve this, without adding namespace prefixes everywhere? --

-- ADDED QUESTION: how to solve the problem also in the case where the inclusion is from another directory, like <xi:include href="subdir/simple_part.xml" />?


Solution

  • Well, it seems that you have a few modifications to perform:

    1) In your XML fragment, you need to declare the same namespace as as the "master" document

     <inner_element xmlns="urn:mynamespace">
       <description>Test</description>
     </inner_element>
    

    2) In the resulting document, an xml:base attribute is automatically set (see XInclude spec, §4.5.5 and C.1) so that you have to declare it in your schema by declaring this attribute and importing the xml namespace like so:

       <xsd:schema
           version="1.0"
           attributeFormDefault="unqualified"
           elementFormDefault="qualified"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns="urn:mynamespace"
           targetNamespace="urn:mynamespace">
    
           <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/03/xml.xsd" />
    
           <xsd:element name="main_element" type="typeMainElement" />
    
           <xsd:complexType name="typeMainElement">
               <xsd:sequence>
                   <xsd:element name="inner_element" type="typeInnerElement" />
               </xsd:sequence>
           <xsd:attribute name="test_attribute" type="xsd:string" use="required" />
           </xsd:complexType>
    
           <xsd:complexType name="typeInnerElement">
               <xsd:sequence>
                   <xsd:element name="description" type="xsd:string" minOccurs="0" />
               </xsd:sequence>
               <xsd:attribute ref="xml:base"/>
           </xsd:complexType>
       </xsd:schema>
    

    Alternative solution with entities

    You need to declare (parsed) entities in a DOCTYPE at the beginning of the "master" document, and use the reference instead of the <xi:include> like so:

    <?xml version="1.0"?>
    <!DOCTYPE main_element [
      <!ENTITY simple_part SYSTEM "simple_part.xml">
    ]>
    <main_element test_attribute="value"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns="urn:mynamespace">
       <!-- call a reference instead of xi:include -->
       &simple_part_1;
    </main_element>
    

    The simple_part.xml will be exactely what you required in the original post:

    <inner_element>
      <description>Test</description>
    </inner_element>