Xml Schema substitution groups / key keyref

J

John Carron

Hi All,

I have written a simple schema (see below) that uses substitution
groups. I don't know if this the correct usage because I'm fairly new to
xml schema.

The structure is as follows:

Request
Report
TargetReference (reference identifier attribute)
Target (identifier attribute)

Example Document:

<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:demo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:demo
Untitled23.xsd">
<DummyReport identifier="10">
<TargetReference identifier="20"/>
</DummyReport>
<DummyTarget identifier="20"/>
</Request>

A valid document can contain a number of reports and targets. The target
reference element should reference only targets in the document and I would
like to enforce this. Does anybody know how to do this? I was initially
thinking along the lines of using the Key and KeyRef elements but don't know
how to do that with substitution groups? Is it possible? I would also like
to enforce that all target identifier attributes are unique. Can this be
done?

Any help would be appreciated.

Regards

Darren

2) Send newsgroup message:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="urn:demo" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:demo" elementFormDefault="qualified"
attributeFormDefault="unqualified">

<!-- Root element request -->
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element ref="ReportGroup"
maxOccurs="unbounded"/>
<xs:element ref="TargetGroup"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<!-- Abstract report type -->
<xs:complexType name="Report" abstract="true">
<xs:sequence>
<xs:element ref="TargetReference"
maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="identifier" type="xs:int"
use="required"/>
</xs:complexType>

<!-- Abstract target type -->
<xs:complexType name="Target" abstract="true">
<xs:attribute name="identifier" type="xs:int"
use="required"/>
</xs:complexType>
<xs:element name="ReportGroup" type="Report" abstract="true"/>
<xs:element name="TargetGroup" type="Target" abstract="true"/>

<!-- Element to join a report to a target -->
<xs:element name="TargetReference">
<xs:complexType>
<xs:attribute name="identifier" type="xs:int"
use="required"/>
</xs:complexType>
</xs:element>

<!-- Reports -->
<xs:element name="DummyReport" substitutionGroup="ReportGroup">
<xs:complexType>
<xs:complexContent>
<xs:extension base="Report"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="AnotherDummyReport"
substitutionGroup="ReportGroup">
<xs:complexType>
<xs:complexContent>
<xs:extension base="Report"/>
</xs:complexContent>
</xs:complexType>
</xs:element>

<!-- Targets -->
<xs:element name="DummyTarget" substitutionGroup="TargetGroup">
<xs:complexType>
<xs:complexContent>
<xs:extension base="Target"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="DummyTarget2" substitutionGroup="TargetGroup">
<xs:complexType>
<xs:complexContent>
<xs:extension base="Target"/>
</xs:complexContent>
</xs:complexType>
</xs:element>

</xs:schema>
 
P

Priscilla Walmsley

Hi,

If you want the identifiers to be unique across all reports and targets,
you can add this to your declaration of the Request element:

<xs:key name="uniqueIDs">
<xs:selector xpath="*"/>
<xs:field xpath="@identifier"/>
</xs:key>

If you only want the identifiers to be unique among targets (and not
reports) and you know all the target element names in advance, you could
use:

<xs:key name="uniqueIDs">
<xs:selector xpath="demo:DummyTarget|demo:DummyTarget2"/>
<xs:field xpath="@identifier"/>
</xs:key>

But, if you only want the identifiers to be unique among targets, and
you don't want to hard code the names in there, I think you'd have to
use a different attribute name for target IDs vs. report IDs.

To enforce the reference, you can use:

<xs:keyref name="validRefs" refer="uniqueIDs">
<xs:selector xpath=".//demo:TargetReference"/>
<xs:field xpath="@identifier"/>
</xs:keyref>

Note that I use a "demo" prefix - You would have to map your target
namespace to a prefix in your schema in order for this to work, because
XPath expressions do not take into account default namespace
declarations.

Hope that helps,
Priscilla
 
J

John Carron

Hi Priscilla ,

Many thanks for the reply. It worked a treat.

Thanks again

Darren
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top