Search code examples
xmlxsd-validation

What is the intended effect of importing/including an XSD into another XSD file when generating an XML file from XSD?


When I generate an XML file from an XSD file that has included one or more XSD files, is the resultant XML file supposed to also include the generated XML from the XSD file(s)?

cake.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://www.examle.com/bakery"
           targetNamespace="https://www.examle.com/bakery"
           elementFormDefault="qualified">
    <xs:include schemaLocation="bakery.xsd"/>
    <xs:include schemaLocation="cakeType.xsd"/>
    <xs:element name="Cake">
        <xs:complexType>
            <xs:all>
                <xs:element name="cakeName" type="xs:string" minOccurs="1" maxOccurs="1"/>
                <xs:element name="cakeType" type="cakeType" minOccurs="0"/>
                <xs:element name="ingredients" type="xs:string" minOccurs="0"/>
                <xs:element name="instructions" type="xs:string" minOccurs="0"/>
            </xs:all>
        </xs:complexType>
    </xs:element>
</xs:schema>

bakery.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://www.examle.com/bakery"
           targetNamespace="https://www.examle.com/bakery"
           elementFormDefault="qualified">
    <xs:element name="Bakery">
        <xs:complexType>
            <xs:all>
                <xs:element name="guid" type="xs:string" minOccurs="1" maxOccurs="1"/>
                <xs:element name="creationDate" type="xs:dateTime" minOccurs="1" maxOccurs="1"/>
                <xs:element name="update" minOccurs="1" maxOccurs="1">
                    <xs:complexType>
                        <xs:all>
                            <xs:element name="updateBy" type="xs:string" minOccurs="1" maxOccurs="1"/>
                            <xs:element name="updateDate" type="xs:dateTime" minOccurs="1" maxOccurs="1"/>
                        </xs:all>
                    </xs:complexType>
                </xs:element>
                <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
                <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
            </xs:all>
        </xs:complexType>
    </xs:element>
</xs:schema>

cakeType.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://www.examle.com/bakery"
           targetNamespace="https://www.examle.com/bakery"
           elementFormDefault="qualified">
    <xs:element name="CakeType"/>
    <xs:simpleType name="cakeType">
        <xs:restriction base="xs:token">
            <xs:enumeration value="angel"/>
            <xs:enumeration value="pound"/>
            <xs:enumeration value="cheese"/>
            <xs:enumeration value="chiffon"/>
            <xs:enumeration value="genoise"/>
            <xs:enumeration value="sponge"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

I understand the generated XML files would look like this:

cake.xsd.xml:

<bak:Cake xmlns:bak="https://www.examle.com/bakery">
  <bak:cakeName>string</bak:cakeName>
  <!--Optional:-->
  <bak:cakeType>chiffon</bak:cakeType>
  <!--Optional:-->
  <bak:ingredients>string</bak:ingredients>
  <!--Optional:-->
  <bak:instructions>string</bak:instructions>
</bak:Cake>

bakery.xsd.xml:

<bak:Bakery xmlns:bak="https://www.examle.com/bakery">
  <bak:guid>string</bak:guid>
  <bak:creationDate>2008-09-28T19:49:45</bak:creationDate>
  <bak:update>
    <bak:updateBy>string</bak:updateBy>
    <bak:updateDate>2014-09-18T17:18:33</bak:updateDate>
  </bak:update>
  <bak:name>string</bak:name>
  <!--Optional:-->
  <bak:description>string</bak:description>
</bak:Bakery>

cakeType.xsd.xml:

<bak:CakeType xmlns:bak="https://www.examle.com/bakery">anyType</bak:CakeType>

Question: Why wouldn't it generate the XML file this way?

(It is including the generated XML of the included XSD files)

cake.xsd.xml: (Does not validate)

<bak:Cake xmlns:bak="https://www.examle.com/bakery">
  <bak:Bakery xmlns:bak="https://www.examle.com/bakery">
    <bak:guid>string</bak:guid>
    <bak:creationDate>2008-09-28T19:49:45</bak:creationDate>
    <bak:update>
      <bak:updateBy>string</bak:updateBy>
      <bak:updateDate>2014-09-18T17:18:33</bak:updateDate>
    </bak:update>
    <bak:name>string</bak:name>
    <!--Optional:-->
    <bak:description>string</bak:description>
  </bak:Bakery>
  <bak:CakeType xmlns:bak="https://www.examle.com/bakery">anyType</bak:CakeType>
  <bak:cakeName>string</bak:cakeName>
  <!--Optional:-->
  <bak:cakeType>chiffon</bak:cakeType>
  <!--Optional:-->
  <bak:ingredients>string</bak:ingredients>
  <!--Optional:-->
  <bak:instructions>string</bak:instructions>
</bak:Cake>

EDIT: I found the answer I was looking for. In order to include the content of the bakery in the cake XML generation, I changed bakery to a type and added a new bakery element to cake. Now, any time I change the bakery content, it will be still included in the cake XML generation.

Changed bakery.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://www.examle.com/bakery"
           targetNamespace="https://www.examle.com/bakery"
           elementFormDefault="qualified">
    <xs:element name="Bakery"/>
    <xs:complexType name="bakeryType">
        <xs:all>
            <xs:element name="guid" type="xs:string" minOccurs="1" maxOccurs="1"/>
            <xs:element name="creationDate" type="xs:dateTime" minOccurs="1" maxOccurs="1"/>
            <xs:element name="update" minOccurs="1" maxOccurs="1">
                <xs:complexType>
                    <xs:all>
                        <xs:element name="updateBy" type="xs:string" minOccurs="1" maxOccurs="1"/>
                        <xs:element name="updateDate" type="xs:dateTime" minOccurs="1" maxOccurs="1"/>
                    </xs:all>
                </xs:complexType>
            </xs:element>
            <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
            <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
        </xs:all>
    </xs:complexType>
</xs:schema>

Changed cake.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://www.examle.com/bakery"
           targetNamespace="https://www.examle.com/bakery"
           elementFormDefault="qualified">
    <xs:include schemaLocation="bakery.xsd"/>
    <xs:include schemaLocation="cakeType.xsd"/>
    <xs:element name="Cake">
        <xs:complexType>
            <xs:all>
                <xs:element name="bakery" type="bakeryType"/>
                <xs:element name="cakeName" type="xs:string" minOccurs="1" maxOccurs="1"/>
                <xs:element name="cakeType" type="cakeType" minOccurs="0"/>
                <xs:element name="ingredients" type="xs:string" minOccurs="0"/>
                <xs:element name="instructions" type="xs:string" minOccurs="0"/>
            </xs:all>
        </xs:complexType>
    </xs:element>
</xs:schema>

Now the generated XML file from the cake.xsd file validates and has the bakery elements included:

<bak:Cake xmlns:bak="https://www.examle.com/bakery">
  <bak:bakery>
    <bak:guid>string</bak:guid>
    <bak:creationDate>2008-09-28T19:49:45</bak:creationDate>
    <bak:update>
      <bak:updateBy>string</bak:updateBy>
      <bak:updateDate>2014-09-18T17:18:33</bak:updateDate>
    </bak:update>
    <bak:name>string</bak:name>
    <!--Optional:-->
    <bak:description>string</bak:description>
  </bak:bakery>
  <bak:cakeName>string</bak:cakeName>
  <!--Optional:-->
  <bak:cakeType>cheese</bak:cakeType>
  <!--Optional:-->
  <bak:ingredients>string</bak:ingredients>
  <!--Optional:-->
  <bak:instructions>string</bak:instructions>
</bak:Cake>

Solution

  • The include element is used to add multiple schemas with the same target namespace to a document.

    cake.xsd needs cakeType.xsd to generate an instance while it may also generate a Bakery type but does not strictly requires it.

    XML instance generated from an xsd will have defined elements and no more than that but could have less. For cake.xsd, 3 of them are of xs:string type and 1 of cakeType type defined in cakeType.xsd but valid because of the <xs:include schemaLocation="cakeType.xsd"/> include:

    <xs:element name="Cake">
        <xs:complexType>
            <xs:all>
                <xs:element name="cakeName" type="xs:string" minOccurs="1" maxOccurs="1"/>
                <xs:element name="cakeType" type="cakeType" minOccurs="0"/>
                <xs:element name="ingredients" type="xs:string" minOccurs="0"/>
                <xs:element name="instructions" type="xs:string" minOccurs="0"/>
            </xs:all>
        </xs:complexType>
    </xs:element>
    

    Generating from cake.xsd returns the same as posted by the OP
    XMLBEANS_LIB='/usr/share/java/xmlbeans/' xsd2inst cake.xsd -name Cake

    bakery.xsd elements are not present on cake.xsd structure and thus will not appear on it, however, Bakery instance can be generated from cake.xsd due to the include

    XMLBEANS_LIB='/usr/share/java/xmlbeans/' xsd2inst cake.xsd -name Bakery
    

    Result

    <bak:Bakery xmlns:bak="https://www.examle.com/bakery">
      <bak:guid>string</bak:guid>
      <bak:creationDate>2008-09-28T22:49:45</bak:creationDate>
      <bak:update>
        <bak:updateBy>string</bak:updateBy>
        <bak:updateDate>2014-09-18T20:18:33</bak:updateDate>
      </bak:update>
      <bak:name>string</bak:name>
      <!--Optional:-->
      <bak:description>string</bak:description>
    </bak:Bakery>
    

    Minimal Cake instance could be

    <bak:Cake xmlns:bak="https://www.examle.com/bakery">
      <bak:cakeName>string</bak:cakeName>
    </bak:Cake>
    

    Generating code with xjcwill generate classes for include xsd as well

    /home/lmc/projects/bin/jaxb-ri/bin/xjc.sh -p cake cake.xsd
    Java major version: 11
    parsing a schema...
    compiling a schema...
    cake/Bakery.java
    cake/Cake.java
    cake/CakeType.java
    cake/ObjectFactory.java
    cake/package-info.java