Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
719 views
in Technique[技术] by (71.8m points)

xml - XSD key/keyref: hierarchical key structure

I'm trying to define some foreign key constraints on an XML schema using xs:key and xs:keyref definitions. I want the structure of the document to be hierarchical in the following way:

<?xml version="1.0" encoding="UTF-8"?>
<tns:root xmlns:tns="http://www.example.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/ SampleSchema.xsd ">
  <parent parentKey="parent1">
    <child childKey="child1"/>
    <child childKey="child2"/>
  </parent>
  <parent parentKey="parent2">
    <child childKey="child1"/>
    <child childKey="child2"/>
  </parent>
  <referrer parentRef="parent1" childRef="child2"/>
</tns:root>

A each parent has a (globally) unique key, defined by parentKey. Each child has key defined by childKey, but childKey is only unique within the scope of its containing parent.

There is then a list of referrers with foreign key references to a particular parent and child.

I'm able to define the keys as I want, simply by putting them on the correct element: the parentKey constraint on the root element, and the childKey constraint on the parent element. I can also define the keyref to parentKey without difficulty.

The problems arise when trying to define a keyref to childKey. I tried defining a simple keyref on the root element to childKey, but that doesn't work since I see no way to select only the child elements under the proper parent subtree. (The Eclipse validator, at least, always simply validates against the content of the last parent subtree in the document...).

I then tried defining a composite key (on root), with:

  • selector = parent
  • field = @parentKey
  • field = child/@childKey

This fails if there is more than one child defined under the parent. That is the correct behavior based on the XSD 1.1 spec, section 3.11.4, item 3, which states that the key has to match at most one node per field definition.

Just to reiterate: if I force childKeys to be globally unique, this is easy to implement; the difficulty is around referencing locally unique childKeys.

Any XSD masters out there have an idea?

For reference, here is a sample XSD, with a failed childKey keyref commented out:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/" xmlns:tns="http://www.example.org/" elementFormDefault="unqualified">

    <element name="root">
        <complexType>
            <sequence>
                <element name="parent" maxOccurs="unbounded" minOccurs="1">
                    <complexType>
                        <sequence>
                            <element name="child" maxOccurs="unbounded" minOccurs="1">
                                <complexType>
                                    <attribute name="childKey" type="string" use="required"/>
                                </complexType>
                            </element>
                        </sequence>
                        <attribute name="parentKey" type="string" use="required"/>
                    </complexType>
                    <key name="childKeyDef">
                        <selector xpath="child"/>
                        <field xpath="@childKey"/>
                    </key>
                </element>
                <element name="referrer" maxOccurs="unbounded" minOccurs="1">
                    <complexType>
                        <attribute name="parentRef" type="string"/>
                        <attribute name="childRef" type="string"/>
                    </complexType>
                </element>
            </sequence>
        </complexType>
        <key name="parentKeyDef">
            <selector xpath="parent"/>
            <field xpath="@parentKey"/>
        </key>
        <keyref name="parentKeyRef" refer="tns:parentKeyDef">
            <selector xpath="referrers"/>
            <field xpath="@parentRef"/>
        </keyref>
<!--        <keyref name="childKeyRef" refer="tns:childKeyDef">-->
<!--            <selector xpath="referrers"/>-->
<!--            <field xpath="@childRef"/>-->
<!--        </keyref>-->
    </element>
</schema>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How about referring to the parent from the child? Even if many children, there will only be one parent, and combining the (parent,child) creates a globally unique key, even though the child key is only unique within its parent:

  <key name="childKeyDef">
    <selector xpath="child"/>
    <field xpath="@childKey"/>
    <field xpath="../@parentKey"/>
  </key>

This doesn't work in xmllint, even though the spec doesn't seem to explicitly disallow this for fields - only for selectors: 3.11.4, (2) says the selector can't be an ancestor (it can only be the context node or descendants.)

Ah, here's the nail in the coffin (looking at specific syntax): the XPath expressions allowed are very limited, and simply don't include ".." http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

So, sorry, this doesn't answer your question, but maybe it will give you some ideas.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...