3

I have two xml schemas:
1) infrastructureRoot.xsd:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:mif="urn:hl7-org:v3/mif" 
  xmlns:v3="urn:hl7-org:v3" 
  xmlns:ex="urn:hl7-org/v3-example" 
  xmlns="urn:hl7-org:v3" 
  targetNamespace="urn:hl7-org:v3" 
  elementFormDefault="unqualified">
  <xs:include schemaLocation="datatypes-base.xsd"/>
  <xs:group name="InfrastructureRootElements">
    <xs:sequence>
      <xs:element name="realmCode" 
                  type="Norwegian_customer" 
                  minOccurs="0" 
                  maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:group>
  <xs:attributeGroup name="InfrastructureRootAttributes"/>
</xs:schema>

2)datatypes-base.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:sch="http://www.ascc.net/xml/schematron"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"  
  elementFormDefault="unqualified">
  <xs:complexType name="customer">
    <xs:sequence>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
      <xs:element name="country" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="Norwegian_customer">
    <xs:complexContent>
     <xs:restriction base="customer">
       <xs:sequence>
         <xs:element name="firstname" type="xs:string"/>
         <xs:element name="lastname" type="xs:string"/>
         <xs:element name="country" 
           type="xs:string" 
           fixed="Norway"/>
     </xs:sequence>
   </xs:restriction>
  </xs:complexContent>
 </xs:complexType>
</xs:schema>

I use following C# code for load the root schema with all includes:

Func<XmlReader> xmlReaderFactory = () =>
                                        {
                                            XmlReaderSettings schemaReaderSettings = new XmlReaderSettings{ DtdProcessing = DtdProcessing.Parse};
                                                XmlTextReader reader = new XmlTextReader(@"InfrastructureRoot.xsd");
                                            return XmlReader.Create(reader, schemaReaderSettings);
                                        };

XmlSchema xsd = XmlSchema.Read(xmlReaderFactory(), (sender, eventArgs) => {});
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.ValidationEventHandler += (sender, eventArgs) => Console.WriteLine(eventArgs.Message + " " + eventArgs.Severity);

try
{
    try
    {
        XmlReaderSettings schemaReaderSettings = new XmlReaderSettings {DtdProcessing = DtdProcessing.Parse};
        XmlReader schemaReader = XmlReader.Create(new DummyReader(), schemaReaderSettings);
        schemaSet.Add(null, schemaReader);
    }
    catch
    {
        // the only thing this code is needed is to set ProhibitDTD to false
        // there is no acceptable public way to do that
    }

    schemaSet.Add(xsd);
    schemaSet.Compile();
    XmlSchemaInclude external = ((XmlSchemaInclude)xsd.Includes[0]);
    String targetNamespace = external.Schema.TargetNamespace;
    Debug.Assert(targetNamespace == null);
}
catch{}

After execution "targetNamespace" value equals "urn:hl7-org:v3" , which is differ from the original schema "datatypes-base.xsd" and breaks validation. Can someone help me with solution?

John Saunders
  • 160,644
  • 26
  • 247
  • 397

3 Answers3

2

When a schema document with an explicit target namespace (like your infrastructureRoot.xsd) uses xs:include to include a schema document which specifies no target namespace (like your datatypes-base.xsd), the declarations in the second schema document are interpreted as though their containing schema document had the same namespace as the including schema document. This mechanism is sometimes referred to as chameleon include -- the declarations in the included schema document taking on this or that target namespace depending on context.

If you want the complex types Customer and NorwegianCustomer not to be captured by the namespace urn:hl7-org:v3, then infrastructureRoot.xsd needs to use xs:import, not xs:include, and the default namespace needs to change to make the reference to type="Norwegian_customer" be a reference to {}Norwegian_customer (that is, a qualified name with Norwegian_customer as its local name and no namespace) instead of being (as it now is) a reference to {urn:hl7-org:v3}Norwegian_customer.

The xs:import construct imports components from a different namespace, while xs:include includes components from the same namespace. Chameleon include can be viewed as a way of making the components in the included schema document be in the same namespace; if it didn't exist, the xs:include in your infrastructure schema would simply raise an error.

C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65
  • I investigated chameleon schema patterns, but still have some questions. We use `Compile` to load the schema and serialize it to our own binary format. And it is still not clear to me why `Compile` sets _targetnamespace_ attribute of included XmlSchema explicitly, making me remove it manually during deserialization. If remove _targetnamespace_ property from included schema just after `Compile` method is called, all will work just fine. Moreover, I believe that source XSD files are valid, because all third-party XSD validation tools I tried do not find any errors. – Konstantyn Varlamov Feb 11 '13 at 17:58
  • Maybe it is not appropriate to use `XmlSchemaSet` or its `Compile` method in our case? How to pre-load all the external schemas then? – Konstantyn Varlamov Feb 11 '13 at 18:00
2

We've been working with HL7v3 and CDA in BizTalk and .Net. To get the CDA schemas to work correctly for validation and just sending messages, I had to add a targetnamespace of urn:hl7-org:v3 to all the "coreschemas" xsd files. After that validation worked and BizTalk messages flowed.

I didn't feel comfortable adding the targetnamespaces to schemas that I don't really own, but it was a decent compromise, since I never actually altered the schemas themselves and things worked afterwards.

Bensonius
  • 1,501
  • 1
  • 15
  • 39
0

The original problem was found during import HL7v3 sources to our custom data storage format and backward export to xml schema. The second schema gets target namespace but not default namespace, which leads to validation fault. Here is second schema export result:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
 xmlns:sch="http://www.ascc.net/xml/schematron"
 xmlns="urn:hl7-org123:v3" 
 xmlns:v3="urn:hl7-org:v3"
 elementFormDefault="unqualified"
 targetNamespace="urn:hl7-org:v3"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="customer">
 <xs:sequence>
   <xs:element name="firstname" type="xs:string" />
   <xs:element name="lastname" type="xs:string" />
   <xs:element name="country" type="xs:string" />
 </xs:sequence>
</xs:complexType>
 <xs:complexType name="Norwegian_customer">
<xs:complexContent mixed="false">
  <xs:restriction base="customer">
    <xs:sequence>
      <xs:element name="firstname" type="xs:string" />
      <xs:element name="lastname" type="xs:string" />
      <xs:element fixed="Norway" name="country" type="xs:string" />
    </xs:sequence>
   </xs:restriction>
</xs:complexContent>
 </xs:complexType>
</xs:schema>

Validation fails on restriction base attribute value. According to target schema design explanation we've two possible solutions:

  1. Use a qualified value with a "v3" prefix.
  2. Add default namespace "xmlns="urn:hl7-org:v3".