views:

336

answers:

1

I'm trying to mimic a relational database structure using XML.

(Just in case anyone is wondering why, my reasons for using XML are: (1) The total amount of data is expected to be small, (2) I need non-programmers to be able to edit some of the input tables, and (3) I want the installation process to be as simple as possible (i.e., no database servers). Also, (4) the people editing the input tables won't have MS Access.)

I expect a large chunk of the database structure to be reused on several projects, so I set out to write two schema (XSD) files. The first would contain definitions for all the basic/reusable tables, while the second would contains definitions for the tables specific to the particular application. Let's say these two files are called Basic.xsd and Specific.xsd.

The good news: I have written my two schema files, and they seem to work as I intended.

The bad news: I wasn't able to write them the way I wanted to. Specifically, I wasn't able to separate the keys/keyrefs for basic data from the keys/keyrefs for the specific data as I had planned. The only thing I could get to work was to lump all keys/keyrefs under a single element in Specific.xsd.

Let me paste in the files here so you can see what I'm talking about.

Basic.xsd

<?xml version="1.0"?>
<xs:schema
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="qualified">
  <xs:complexType name="tables">
    <xs:sequence>
      <xs:element name="basic1Table" type="basic1Table" />
      <xs:element name="basic2Table" type="basic2Table" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="basic1Table">
    <xs:sequence>
      <xs:element name="basic1" type="basic1" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="basic2Table">
    <xs:sequence>
      <xs:element name="basic2" type="basic2" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="basic1">
    <xs:sequence>
      <xs:element name="id" type="xs:int" />
      <xs:element name="value" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="basic2">
    <xs:sequence>
      <xs:element name="id" type="xs:int" />
      <xs:element name="value" type="xs:string" />
      <xs:element name="basic1Id" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Specific.xsd

<?xml version="1.0"?>
<xs:schema
  xmlns="example"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="example"
  targetNamespace="example"
  elementFormDefault="qualified">
  <xs:redefine schemaLocation="Basic.xsd">
    <xs:complexType name="tables">
      <xs:complexContent>
        <xs:extension base="tables">
          <xs:sequence>
            <xs:element name="specific1Table" type="specific1Table" />
            <xs:element name="specific2Table" type="specific2Table" />
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>
  <xs:element name="tables" type="tables">
    <xs:key name="basic1Key"> <!-- Should be in Basic.xsd -->
      <xs:selector xpath="tns:basic1Table/tns:basic1" />
      <xs:field xpath="tns:id" />
    </xs:key>
    <xs:key name="basic2Key"> <!-- Should be in Basic.xsd -->
      <xs:selector xpath="tns:basic2Table/tns:basic2" />
      <xs:field xpath="tns:id" />
    </xs:key>
    <xs:key name="specific1Key">
      <xs:selector xpath="tns:specific1Table/tns:specific1" />
      <xs:field xpath="tns:id" />
    </xs:key>
    <xs:key name="specific2Key">
      <xs:selector xpath="tns:specific2Table/tns:specific2" />
      <xs:field xpath="tns:id" />
    </xs:key>
    <xs:keyref name="basic2ToBasic1KeyRef" refer="basic1Key"> <!-- Should be in Basic.xsd -->
      <xs:selector xpath="tns:basic2Table/tns:basic2" />
      <xs:field xpath="tns:basic1Id" />
    </xs:keyref>
    <xs:keyref name="specific2ToSpecific1KeyRef" refer="specific1Key">
      <xs:selector xpath="tns:specific2Table/tns:specific2" />
      <xs:field xpath="tns:specific1Id" />
    </xs:keyref>
    <xs:keyref name="specific2ToBasic1KeyRef" refer="basic1Key">
      <xs:selector xpath="tns:specific2Table/tns:specific2" />
      <xs:field xpath="tns:basic1Id" />
    </xs:keyref>
  </xs:element>
  <xs:complexType name="specific1Table">
    <xs:sequence>
      <xs:element name="specific1" type="specific1" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="specific2Table">
    <xs:sequence>
      <xs:element name="specific2" type="specific2" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="specific1">
    <xs:sequence>
      <xs:element name="id" type="xs:int" />
      <xs:element name="value" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="specific2">
    <xs:sequence>
      <xs:element name="id" type="xs:int" />
      <xs:element name="value" type="xs:string" />
      <xs:element name="basic1Id" type="xs:int" />
      <xs:element name="specific1Id" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Sample XML file that validates successfully

<?xml version="1.0" encoding="utf-8"?>
<tables
  xmlns="example"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="example Specific.xsd">
  <basic1Table>
    <basic1>
      <id>1</id>
      <value>value1</value>
    </basic1>
    <basic1>
      <id>2</id>
      <value>value2</value>
    </basic1>
    <basic1>
      <id>3</id>
      <value>value3</value>
    </basic1>
  </basic1Table>
  <basic2Table>
    <basic2>
      <id>1</id>
      <value>value1</value>
      <basic1Id>1</basic1Id>
    </basic2>
    <basic2>
      <id>2</id>
      <value>value2</value>
      <basic1Id>2</basic1Id>
    </basic2>
    <basic2>
      <id>3</id>
      <value>value3</value>
      <basic1Id>3</basic1Id>
    </basic2>
  </basic2Table>
  <specific1Table>
    <specific1>
      <id>1</id>
      <value>value1</value>
    </specific1>
    <specific1>
      <id>2</id>
      <value>value2</value>
    </specific1>
    <specific1>
      <id>3</id>
      <value>value3</value>
    </specific1>
  </specific1Table>
  <specific2Table>
    <specific2>
      <id>1</id>
      <value>value1</value>
      <basic1Id>1</basic1Id>
      <specific1Id>1</specific1Id>
    </specific2>
    <specific2>
      <id>2</id>
      <value>value2</value>
      <basic1Id>2</basic1Id>
      <specific1Id>2</specific1Id>
    </specific2>
    <specific2>
      <id>3</id>
      <value>value3</value>
      <basic1Id>3</basic1Id>
      <specific1Id>3</specific1Id>
    </specific2>
  </specific2Table>
</tables>

So, the keys basic1Key and basic2Key and the keyref basic2ToBasic1KeyRef are in Specific.xsd. I'd like to figure out a way to move them to Basic.xsd, while keeping all the keys/keyrefs involving "specific" data in Spcific.xsd. The problem is that keys/keyrefs are tied to elements, not to types. So, I can't place the keys/keyrefs inside the xs:complexType definitions where they belong (at least in my mind).

One thought I had was to separate the "tables" element into two separate elements: basicTables and specificTables, but there is an added complication here that makes that difficult (impossible?). Notice the keyref, specific2ToBasic1KeyRef. This creates a link between the specific2 table and the basic1 table. So, I would need this keyref to "jump across" elements, which I don't think is possible.

To summarize, how can I make it so that all the table definitions, keys, and keyrefs for "basic" data are stored in Basic.xsd, while all additional definitions needed for the specific implementation are stored in Specific.xsd? If it's not possible and what I've pasted in here is as good as I'm going to get, that would be nice to know too.

Thanks for your help!

-Dan

A: 

Dan, did you found a solution for this? I need something like you described because I can't edit original xsd file but I would like to add some constraints to its structure.

Filip
It sounds like your problem may me different. Even if you can't edit the original xsd file, you should still be able to use `redefine` in your new xsd file to add more tables to it and also add keys and keyrefs to guarantee that id's are unique and referenced properly (see "Specific.xsd" in my example above).
DanM