Re: group or abstract type?

Consider the following schema which, if I understood the email below
correctly, is valid:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xs:element name="AbstractMenuEntry" abstract="true"/>
	<xs:element name="MenuStructure">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="AbstractMenuEntry"
maxOccurs="unbounded"/>
			</xs:sequence>
		</xs:complexType>
		<xs:unique name="menuIdConstraint">
			<xs:selector xpath="MenuEntry"/>
			<xs:field xpath="@menuId"/>
		</xs:unique>
	</xs:element>
	<xs:element name="MenuEntry" substitutionGroup="AbstractMenuEntry">
		<xs:complexType>
			<xs:attribute name="menuId"/>
		</xs:complexType>
	</xs:element>
</xs:schema>

This validates in XML Spy, but not in MSXML4.0 and SQC2.1.1. Until recently,
I was using XML Spy and life was easy, but I also need to use MSXML4.0 and I
get the following error message from SQC2.1.1: 

SEVERITY: 0
ERROR TYPE: 2
MESSAGE
No node in element MenuStructure corresponds to <xs:selector
xpath="MenuEntry"/>

 defined in <xs:unique name="menuIdConstraint">
    <selector xpath="MenuEntry"/>
    <field xpath="@menuId"/>
</xs:unique>
. Invalid XPath starting from MenuStructure:MenuEntry.


XML Spy doesn't even check if menuId exists anywhere, that is, changing
<xs:field xpath="@menuId"/> to <xs:field xpath="@menuId777"/> would not
generate an error. Would this be a W3C conformant schema even if menuId777
does not exist? 

With SQC2.1.1, menuId is not found within the context of MenuStructure even
though it is there by substitution of the AbstractMenuEntry abstract
element. It seems that, this validator seeks to resolve the field xpath and
this without checking all the possible substitutions. Even if it were to try
to check, it is an impossible feat, since another schema file may include
this one and define a new element with an AbstractMenuEntry substitution
group. So requiring the existence of the element/attribute pointed to by the
xpath is limiting when working with abstract elements. I am stuck. How can I
specify (in a way that pleases SQ2.1.1 and MSXML4.0) that all the MenuEntry
elements of MenuStructure must have unique menuId? I would be pleased to
hear of a workaround to this problem.   

What does the W3C consider as valid in this case?

Thanks in advance.


-----Original Message-----
Date: Wed, 9 Jan 2002 10:15:58 +0000
From: Jeni Tennison <jeni@jenitennison.com>
Message-ID: <83178716961.20020109101558@jenitennison.com>
To: "Patrick Lisser" <patrick.lisser@canoo.com>
CC: xmlschema-dev@w3.org
Subject: Re: group or abstract type?

Hi Pat,

> Now I wonder whether such [identity] constraints work
> better/easier/not-at-all with model group and substitution group (I
> didn't try hard yet, but until now nothing worked. Have first to
> read more about these unique/key constraints).

To summarise the way identity constraints work... The location of the
identity constraint determines its scope. The xs:selector XPath points
to all the elements that have identities within that scope. The
xs:field XPaths go from those elements to the elements/attributes that
give them their identity.

Unfortunately (in some ways), identity constraints work with a
different kind of model of the instance document than the rest of XML
Schema, and don't allow you to select elements based on things like:

  - their membership of substitution groups
  - their type
  - the group in which they're declared

All that the XPaths 'see' when they're evaluated is the node tree of
the instance document. So if you do:

<xs:element name="MenuStructure">
  ...
  <xs:unique name="menuIdConstraint">
    <xs:selector xpath="AbstractMenuEntry"/>
    <xs:field xpath="@menuId"/>
  </xs:unique>
</xs:element>

all it means is that all the AbstractMenuEntry elements that are
direct children of the MenuStructure element must have unique values
for their menuId attributes. This constraint does not apply to any
other child elements of the MenuStructure element (so actually imposes
no constraint at all, since AbstractMenuEntry elements never appear in
the instance document).

To say "all child elements of a MenuStructure element that have a
menuId attribute must take a different value for that menuId
attribute", you need to use a wildcard:

<xs:element name="MenuStructure">
  ...
  <xs:unique name="menuIdConstraint">
    <xs:selector xpath="*"/>
    <xs:field xpath="@menuId"/>
  </xs:unique>
</xs:element>

Alternatively, you could list the possible elements, but I think this
would lead to a lot of work overall, considering you want people to be
able to extend the list of possible children.

> I.e. should the constraints above work even if there are some menus
> (e.g. <Spacer/>) which do not have a menuId (I'd guess that it works
> with the unique constraint but not with the key costraint)?

That's right - the unique constraint just checks that those elements
that have values for whatever fields you use have unique combinations
of values, whereas the key constraint also checks that all the
elements you select have values for those fields. I think that the
unique constraint is the one that you should use.

> Or would I have to specify a constraint covering the concrete menu
> entries, which would be MenuEntry and DynamicMenuEntry, directly?

See above. You could do:

<xs:element name="MenuStructure">
  ...
  <xs:unique name="menuIdConstraint">
    <xs:selector xpath="MenuEntry | DynamicMenuEntry"/>
    <xs:field xpath="@menuId"/>
  </xs:unique>
</xs:element>

but if someone wanted to add a possible element to the list, they'd
have to redefine the MenuStructure element. I think a wildcard is
probably better if you want to support extensions to the content
model.

Cheers,

Jeni

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

Received on Thursday, 5 September 2002 17:01:16 UTC