Question

I would like to create an XSD that defines an attribute which can be placed on elements from other schemas, or elements that are not in any schema. For example, the schema would look something like this:

<xs:schema id="MySchema"
    targetNamespace="http://tempuri.org/MySchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/MySchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:attribute name="myAttribute" />
</xs:schema>

And the document might look something like this:

<someElement xmlns="http://tempuri.org/OtherSchema" xmlns:m="http://tempuri.org/MySchema">
  <someOtherElement someAttribute="value" m:myAttribute="value2" />
</someElement>

"OtherSchema" for this example looks like this:

<xs:schema id="OtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="someElement">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" name="someOtherElement">
          <xs:complexType>
            <xs:attribute name="someAttribute" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

A complete example, including a C# console application which performs validation, can be downloaded from http://dl.getdropbox.com/u/407740/SchemaTest.zip. My goal is to make this validate without having to modify "OtherSchema". Is this possible?

Was it helpful?

Solution

I had to add a wrapper, to import the two different schema into one (because xmllint only accepts a single xml schema):

<xs:schema id="Wrapper" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import schemaLocation="MySchema.xsd" namespace="http://tempuri.org/MySchema"/>
  <xs:import schemaLocation="OtherSchema.xsd" namespace="http://tempuri.org/OtherSchema"/>
</xs:schema>

The only way I could get something like the Question to work was to edit OtherSchema,xsd (which is not allowed by the question), so append an attribute wildcard (after the existing one):

 <xs:attribute name="someAttribute" />
 <xs:anyAttribute namespace="##other"/>

I'm not enough of an expert of XML Schema to say "this is impossible", but it seems impossible to me.

One problem with your proposal is that you don't specify where the new attribute should appear. Usually, if you declare an attribute (or a complexElement, modelgroup etc), you are free to refer to it or not. If you don't explicitly refer to it, it has no effect. Therefore, I think your proposal will be treated as an attribute that is declared, but not referred to.

What you really want is a way to say "add this attribute to every existing complexType" - but you don't say this. And, unfortunately, there doesn't seem to be a way to say this. (there isn't even a way to say "add this attribute to this specific existing complexType" - you have to include it in the original definition or not at all.)

One way to partly do it is to <redefine> types in another schema - I'll add this in a second answer.

OTHER TIPS

You can redefine schema, extending them however you like. In this way, you can modify the definitions of an existing schema without actually changing the file. BUT IT WON'T WORK FOR YOUR EXAMPLE as given, because one can't redefine elements (only complexTypes, etc. see http://www.w3.org/TR/xmlschema-1/#element-redefine). Therefore, I've broken your example into explicit complexTypes, so they are exposed for redefinition.

RedefineOtherSchema.xsd:

<xs:schema id="RedefineOtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:m="http://tempuri.org/MySchema">          <!-- for the ref -->

  <xs:import schemaLocation="MySchema.xsd"
    namespace="http://tempuri.org/MySchema"/>       <!-- import -->

  <xs:redefine schemaLocation="OtherSchema.xsd">    <!-- redefine -->
    <xs:complexType name="SomeOtherElement">
      <xs:complexContent>
        <xs:extension base="SomeOtherElement">
          <xs:attribute ref="m:myAttribute" />      <!-- the ref -->
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>
</xs:schema>

OtherSchema:

<xs:schema id="OtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="someElement" type="SomeElement"/>

    <xs:complexType name="SomeElement">
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded"
                    name="someOtherElement" type="SomeOtherElement"/>
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="SomeOtherElement">
      <xs:attribute name="someAttribute" />
    </xs:complexType>
</xs:schema>

MySchema: (unchanged)

<xs:schema id="MySchema"
    targetNamespace="http://tempuri.org/MySchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/MySchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:attribute name="myAttribute"/>
</xs:schema>

Why <complexContent>? The redefinition must be an extension (or restriction) of the existing type - that's how it modifies the previous definition. Extension must be in <complexContent> (I believe).

Why <import>? You can't define things in more than one namespace in a xsd (there is only one "targetNamespace"). But you can get around this by importing a definition from another xsd (then you've not "defining" it). [is there is another way?]

HTH :-)

This is exactly what NVDL (Namespace-based Validation and Dispatching Language) provides. It allows to combine multiple schemas/vocabularies to validate a document without the need to change those schemas. NVDL is an ISO standard.

A working NVDL script that handles your case is below

<rules xmlns="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0" startMode="other">
  <mode name="other">
    <namespace ns="http://tempuri.org/OtherSchema">
      <validate schema="other.xsd" useMode="validateMyAttributes"/>
    </namespace>
  </mode>
  <mode name="validateMyAttributes">
    <namespace ns="http://tempuri.org/MySchema" match="attributes">
      <validate schema="my.xsd"/>
    </namespace>
  </mode>
</rules>

Basically it says validate what it is on the ...tempuri.org/OtherSchema namespace with the other.xsd schema and the attributes from ...tempuri.org/MySchema with the my.xsd schema.

For more info about NVDL see www.nvdl.org. The above script was tested with oNVDL.

Consider xsi:nil, xsi:schemaLocation and xsi:noNamespaceSchemaLocation. The answer is yes.

It also wouldn't have taken long to try it out and see.


You were missing a targetNamespace in the schema. Try this:

<xs:schema xmlns="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="MySchema">
  <xs:attribute name="myAttribute" />
</xs:schema>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top