Re: Limited implementation of Global Attributes?

Hi Paul,

> I'm encountering a rather unique error that may have to do with the actual
> schema specification (verified with separate parsing engines) I'd like to
> get someone else's eyes on.  Take the following snippet of XML:
>
> ---------
> <TopLevelElement
>   xmlns="http://someurl.com/namespace/data/1.0"
>   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>   xsi:schemaLocation="http://someurl.com/namespace/data/1.0/thisForm.xsd">
>
>   <SecondLevelElement xmlns:Action="Add">
>     ...
>   </SecondLevelElement>
> </TopLevelElement>
> ---------
>
> Note the "xmlns:" namespace qualifier in front of "Action", basically
> declaring this attribute to exist in the currently defined space.  I
> *should* be able to take this off and simply have:
>
> <SecondLevelElement Action="Add">

Just to check that you're understanding what the xmlns: prefix
actually does in the above. The attribute xmlns:Action="Add" attribute
is a namespace declaration, that states that the prefix 'Action' is
associated with the namespace 'Add' for the SecondLevelElement and all
its descendants. It works in just the same way as all the other
namespace declarations that you're using. Schema-aware processors
won't report the xmlns:Action attribute as an attribute, because
namespace declarations have a very specific purpose.

This is *very* different from the attribute Action="Add" in your
second example, which isn't a namespace declaration, but is a proper
attribute. As with all attributes that lack prefixes, the Action
attribute is in no namespace (this is the major way in which elements
and attributes differ in terms of namespace-aware processing - the
default namespace applies to elements that don't have prefixes, but
doesn't apply to attributes without prefixes).

Let's take a third example:

<TopLevelElement
  xmlns="http://someurl.com/namespace/data/1.0"
  xmlns:ns="http://someurl.com/namespace/data/1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://someurl.com/namespace/data/1.0 thisForm.xsd">

  <SecondLevelElement ns:Action="Add">
    ...
  </SecondLevelElement>

</TopLevelElement>

Here, the Action element has a 'ns' prefix, which is associated
(through a namespace declaration on the TopLevelElement) with the
namepsace http://someurl.com/namespace/data/1.0. This Action attribute
is therefore in the http://someurl.com/namespace/data/1.0 namespace.

> XMLSpy: This file is not valid: Unexpected attribute 'Action' - the parent
> element requires some attributes to be qualified, because your Schema uses
> attributeForm='qualified' or global attributes.  You may need to specify a
> prefix for your schema namespace.
>
> XMLSpy makes a great deal more sense, but still doesn't quite explain the
> situation.  The "Action" attribute *is* a global definition, but it's been
> incorporated into the current namespace.

Yes, that's what XMLSpy is saying. When you declare an attribute at
the top level of the schema, you create a global declaration. Global
declarations differ from local declarations in that *all* global
declarations declare attributes as being in the target namespace of
the schema. So when you do:

> <xs:schema
>   xmlns="http://someurl.com/namespace/data/1.0"
>   xmlns:xs="http://www.w3.org/2001/XMLSchema"
>   targetNamespace="http://someurl.com/namespace/data/1.0"
>   elementFormDefault="qualified"
>   attributeFormDefault="unqualified">
>
>   <xs:attribute name="Action">
...
>   </xs:attribute>
> </xs:schema>

you declare an Action attribute in the namespace
http://someurl.com/namespace/data/1.0. Of the three earlier examples
of the instance document, you'll recall that the only version in which
the Action attribute was in the http://someurl.com/namespace/data/1.0
namespace was the third example, in which the Action attribute had a
prefix that was associated with that namespace.

When you refer to the attribute in the following:

> <xs:schema
>   xmlns="http://someurl.com/namespace/data/1.0"
>   targetNamespace="http://someurl.com/namespace/data/1.0"
>   xmlns:xs="http://www.w3.org/2001/XMLSchema"
>   elementFormDefault="qualified"
>   attributeFormDefault="unqualified">
> 
>   <xs:include schemaLocation="GenericTypes.xsd"/>
>   <xs:element name="TopLevelElement">
>     <xs:complexType>
>       <xs:sequence>
>           ...
>         <xs:element name="SecondLevelElement" maxOccurs="unbounded">
>           <xs:complexType>
>             <xs:complexContent>
>               <xs:extension base="SecondLevelType">
>                 <xs:attribute ref="Action"/>
>               </xs:extension>
>             </xs:complexContent>
>           </xs:complexType>
>         </xs:element>
>           ...
>       </xs:sequence>
>     </complexType>
>   </xs:element>
> </xs:schema>

The ref attribute holds a qualified name. This qualified name is
interpreted relative to the default namespace declarations in force on
the xs:attribute element. The default namespace at that point is the
http://someurl.com/namespace/data/1.0 namespace. Therefore you're
referring to the Action attribute in the
http://someurl.com/namespace/data/1.0 namespace. So what you're saying
is that the SecondLevelElement can have an attribute called Action in
the http://someurl.com/namespace/data/1.0 namespace (and must not have
any other attributes).

XMLSpy gives you an error because it finds an Action attribute in no
namespace. You haven't stated that the SecondLevelElement can have
such an attribute, which is why it's a validity error.

So you need to decide what you want -- do you want the Action
attribute to be in the http://someurl.com/namespace/data/1.0 namespace
or not? If you do, then you have to change the instance documents so
that the http://someurl.com/namespace/data/1.0 namespace is declared
with a namespace and the Action attribute is given that namespace
wherever it's used.

If you don't, you need to find a way of declaring the Action attribute
*locally* so that it can remain "unqualified", which means that it
isn't in the target namespace of the schema. The easiest way to do
that (and still make the Action attribute reusable) is to declare it
within an attribute group, as follows:

<xs:schema
  xmlns="http://someurl.com/namespace/data/1.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://someurl.com/namespace/data/1.0"
  elementFormDefault="qualified"
  attributeFormDefault="unqualified">

<xs:attributeGroup name="ActionAttr">
  <xs:attribute name="Action">
    ...
  </xs:attribute>
</xs:attributeGroup>

</xs:schema>

In this schema, the Action attribute is declared locally, within an
attribute group. It doesn't have a form attribute of its own, and the
attributeFormDefault of the schema is 'unqualified', so the Action
attribute is declared as being in no namespace.

In the schema that uses this GenericTypes.xsd schema, you can then
pull in the Action attribute by referring to the ActionAttr attribute
group as follows:

<xs:schema
  xmlns="http://someurl.com/namespace/data/1.0"
  targetNamespace="http://someurl.com/namespace/data/1.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="qualified"
  attributeFormDefault="unqualified">

  <xs:include schemaLocation="GenericTypes.xsd"/>
  <xs:element name="TopLevelElement">
    <xs:complexType>
      <xs:sequence>
          ...
        <xs:element name="SecondLevelElement" maxOccurs="unbounded">
          <xs:complexType>
            <xs:complexContent>
              <xs:extension base="SecondLevelType">
                <xs:attributeGroup ref="ActionAttr"/>
              </xs:extension>
            </xs:complexContent>
          </xs:complexType>
        </xs:element>
          ...
      </xs:sequence>
    </complexType>
  </xs:element>
</xs:schema>

It's only a small change, but it makes all the difference in the world
to the namespace in which the attribute is declared, and therefore
whether or not you need to use a prefix when you use it or not.

I should note that this revised schema in fact makes the third example
(in which the attribute is given a prefix and therefore belongs to the
http://someurl.com/namespace/data/1.0 namespace) invalid.

I hope that clears things up,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/

Received on Saturday, 23 February 2002 18:34:45 UTC