3

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?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
jon without an h
  • 572
  • 1
  • 4
  • 17
  • Are someElement, someOtherElement and someAttribute defined in OtherSchema? I think you want myAttribute to be required on *all* elements, without it being being defined on those elements. That seems impossible to me. I tried it, and of course it doesn't work. John says it works for xsi:nil etc, but they are built-in to the XML Schema world, and could be (and sound like) special cases to me, as jelovirt suggested. – 13ren Jun 01 '09 at 14:02
  • Yes, as far as I can tell the attributes from schema-instance are handled specially. I can construct an OtherSchema which makes the above example valid, but I would like this to work without having to modify OtherSchema. – jon without an h Jun 02 '09 at 02:36
  • @jon please add a complete example that should do what you want, but doesn't, so that it can be run directly. That is, an "OtherSchema", namespaces that work, and anything else needed, so it can just be cut and pasted. I think this is an interesting question, but it's also quite sophisticated and abstract, and it will help a lot if you make it as concrete and specific as possible. – 13ren Jun 02 '09 at 17:08
  • I didn't realize this question was so esoteric ... I have updated with concrete documents and a code example. Thanks for your time! – jon without an h Jun 03 '09 at 04:22
  • @jon: Do you still have the same problem after adding targetNamespace? – John Saunders Jun 03 '09 at 04:42
  • @John: Yes, the updated examples still fail validation. – jon without an h Jun 03 '09 at 20:24

4 Answers4

1

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.

13ren
  • 11,887
  • 9
  • 47
  • 64
1

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 :-)

13ren
  • 11,887
  • 9
  • 47
  • 64
  • This is an interesting approach and it's possible I'll be able to adapt it to what I'm trying to do. It still places constraints on the third-party schema as you cannot redefine an inline type (and the particular schema I'm working with has several). But, it looks like you are right in saying that my original stated goal is not achievable, and this is a pretty good workaround. – jon without an h Jun 04 '09 at 17:30
  • I agree: it's common to define elements instead of types, and elements can't be defined. BTW: I think that types that are inline within a top-level type definition (not a top-level element) can be redefined, by redefining the type it is inside of.... (I haven't tried it, but it makes sense), but this doesn't help for top-level elements as far as I can see. – 13ren Jun 04 '09 at 19:21
  • It would be worth asking on the xml-dev mailing list (there are some deep experts there, including some of the originators of XML Schema). The feature you want would be very useful - maybe they have a workaround. – 13ren Jun 04 '09 at 19:23
0

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.

George Bina
  • 1,171
  • 7
  • 7
-1

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>
John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • All your examples are from XML Schema instance namespace, attributes used by XML Schema itself. Could you give an example of OtherSchema schema that will allow MySchema attributes without declaring them in OtherSchema? – jelovirt May 31 '09 at 18:11
  • It doesn't matter. Try it and find out. – John Saunders May 31 '09 at 18:12
  • The example was actually a schema and a separate document. I have updated the question to reflect that. The point is, I have no control over the contents of OtherSchema. I want this attribute to be able to be placed on any element regardless of how it is defined in the schema it comes from. Obviously the example does not work or I would not have had a question. What are you suggesting I try? – jon without an h Jun 01 '09 at 03:50
  • What doesn't work? As it is now, if you reference your schema when the document is being validated, it should validate. Is there an exception? Can you show the code being used to validate it? – John Saunders Jun 01 '09 at 13:03
  • Currently I am using the XML editor in Visual Studio 2008. I have confirmed that VS is aware of my sample schema but when it validates the sample document it gives the error "The 'MySchema:myAttribute' attribute is not declared." – jon without an h Jun 02 '09 at 02:15
  • Actually, I tried it and it validated. However, I think that it should not have validated. In retrospect, unless a schema permits arbitrary attributes to be used, they are not valid. The answser from 13ren below appears to be the correct one, but as he said, it won't work for your example, since it uses elements and not complexType. – John Saunders Jun 03 '09 at 19:39