简体   繁体   中英

Adding a child element to an element in another namespace with XML schema

I have an XSD for a certain XML schema in a certain namespace, let's call it http://mydomain/schema1 . Here's an example of what a corresponding XML file might look like:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="http://mydomain/schema1">
  <a>
    <b />
  </a>
</root>

Now, I'd like to define a new schema, let's call it http://mydomain/schema2 , that extends the first one, allowing me to place new elements within the existing elements, like this:

<root xmlns="http://mydomain/schema1" xmlns:s2="http://mydomain/schema2">
  <a>
    <b>
     <s2:c>...</s2:c>
    </b>
  </a>
</root>

Is this possible using XML schema? Given the following XSD for http://mydomain/schema1 , what would the XSD for http://mydomain/schema2 look like and how would it modify the complex type definition for B ?

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="schema1"
           targetNamespace="http://mydomain/schema1"
           elementFormDefault="qualified"
           xmlns="http://mydomain/schema1"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="root" type="Root" />

  <xs:complexType name="Root">
    <xs:sequence>
      <xs:element name="a" type="A" />
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
  
  <xs:complexType name="A">
    <xs:sequence>
      <xs:element name="b" type="B" />
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
  
  <xs:complexType name="B">
    <xs:sequence>
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The actual goal would be to take an input document that adheres to http://mydomain/schema1 (only!) and then return it extended with elements defined by http://mydomain/schema2 . I'd like to allow my end users to validate both the input document and the extended return document, against the respective schema definitions, so I need to publish both schemas.

Our current workaround is that we parse the original XSD, modify the schema definition to include the additional elements, then update all namespaces to http://mydomain/schema2 and publish the resulting schema. The result looks like a superset of http://mydomain/schema1 , but really defines a different namespace for all the elements, even those already present in http://mydomain/schema1 . When we take the actual input XML, we first rewrite the namespaces, then add the new elements. That works, but feels somewhat clumsy - and of course, http://mydomain/schema2 isn't really a superset of http://mydomain/schema1 , it just looks like one.

you can use the extension part in the complex type to add new elements to the complex type. like this:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://tempuri.org/Childs" targetNamespace="http://tempuri.org/Childs">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Child" type="ChildType" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="ChildType">
        <xs:sequence>
            <xs:element type="xs:string" name="Name"/>
            <xs:element type="xs:date" name="DayOfBirth"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

This childs.xsd xml schema file will create the below xml

<root xsi:schemaLocation="http://tempuri.org/Childs childs.xsd" xmlns="http://tempuri.org/Childs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Child>
        <Name>String</Name>
        <DayOfBirth>1967-08-13</DayOfBirth>
    </Child>
    <Child>
        <Name>String</Name>
        <DayOfBirth>1967-08-13</DayOfBirth>
    </Child>
</root>

now in the parent.xsd file the childs.xsd gets imported and therefor the complex types in that schema can be used.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/Parents" xmlns:c="http://tempuri.org/Childs" targetNamespace="http://tempuri.org/Parents" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:import namespace="http://tempuri.org/Childs" schemaLocation="Childs.xsd"/>
    <xs:element name="Root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Parent">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Childs" type="ChildType" maxOccurs="4"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="ChildType">
        <xs:complexContent>
            <xs:extension base="c:ChildType">
                <xs:sequence>
                    <xs:element name="Gender" type="xs:string"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>

Because the complex type ChildType in the parent.xsd uses the complex ChildType from the Childs.xsd (and therefor needs to be prefixed with the namespace prefix) as a base it will have the element Name and DayOfBirth. The extension part can be used to add content below the base content. Like in this example Gender has been added.

the example xml for the parent.xsd is:

<Root xsi:schemaLocation="http://tempuri.org/Parents parents.xsd" xmlns="http://tempuri.org/Parents" xmlns:c="http://tempuri.org/Childs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Parent>
        <Childs>
            <c:Name>String</c:Name>
            <c:DayOfBirth>1967-08-13</c:DayOfBirth>
            <Gender>String</Gender>
        </Childs>
        <Childs>
            <c:Name>String</c:Name>
            <c:DayOfBirth>1967-08-13</c:DayOfBirth>
            <Gender>String</Gender>
        </Childs>
    </Parent>
</Root>

This is not intended to be an answer...just seeking further clarifications in an effort to understand what you are trying to accomplish.

I'd like to allow my end users to validate both the input document and the extended return document, against the respective schema definitions, so I need to publish both schemas.

It's not clear (to me, anyway) why your users would need to re-validate the extended document. If your program has worked correctly, surely it must produce an XML document that conforms to the new XSD?

When we take the actual input XML, we first rewrite the namespaces, then add the new elements. That works, but feels somewhat clumsy

Comparing two XSDs to identify where the new elements need to go is a non-trivial task, unless you can rely on the XSD being very simple. Same applies to adding the new elements automatically. I hope you have strong governance around the design of your XSDs to prevent them becoming complex.

The XML Schema specification provides a number of different ways to change and extend complex type definitions. I do not understand your requirements well enough to recommend a solution, but I recommend that you read XML Schema Primer . It is quite readable and it may offer new options that you have not even considered yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM