XSD key / keyref:分层键结构

时间:2009-05-21 03:45:15

标签: xml schema xsd

我正在尝试使用xs:key和xs:keyref定义在XML模式上定义一些外键约束。我希望文档的结构按以下方式分层:

<?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>

每个父级都有一个(全局)唯一键,由parentKey定义。每个子项都有由childKey定义的键,但是childKey在其包含的父的范围内是唯一的。

然后有一个引用者列表,其中包含对特定父母和子女的外键引用。

我可以根据需要定义键,只需将它们放在正确的元素上:根元素上的parentKey约束和父元素上的childKey约束。我也可以毫不费力地将keyref定义为parentKey。

尝试为childKey定义keyref时出现问题。我尝试在root元素上定义一个简单的keyref到childKey,但是这不起作用,因为我看不到只选择正确父子树下的子元素。 (Eclipse验证器,至少,总是简单地验证文档中最后父子树的内容......)。

然后我尝试使用:

定义复合键(在根目录上)
  • selector = parent
  • field = @parentKey
  • field = child / @ childKey

如果父项下定义了多个子项,则会失败。这是基于XSD 1.1 spec第3.11.4节第3项的正确行为,该条款规定密钥必须与每个字段定义最多匹配一个节点。

重申一下:如果我强迫childKeys全局唯一,这很容易实现;困难在于引用本地唯一的childKeys。

任何XSD大师都有想法吗?

作为参考,这里是一个示例XSD,注释掉了一个失败的childKey keyref:

<?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>

3 个答案:

答案 0 :(得分:2)

如何提及孩子的父母?即使很多孩子,也只有一个父,并且(parent,child)组合创建了一个全局唯一的密钥,即使子密钥在其父密钥中是唯一的:

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

这在xmllint中不起作用,即使规范似乎没有明确禁止这个字段 - 仅适用于选择器:3.11.4,(2)说选择器可以不是一个祖先(它只能是上下文节点或后代。)

啊,这是棺材中的钉子(查看特定语法):允许的XPath表达式非常有限,并且根本不包含“..”http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

所以,对不起,这不能回答你的问题,但也许会给你一些想法。

答案 1 :(得分:1)

一个丑陋的解决方案是更改XML格式,以便parentKey包含在每个子节点中,如下所示:

<parent>
  <child parentKey="parent1" childKey="child1"/>
  <child parentKey="parent1" childKey="child2"/>
</parent>

我认为你的情况非常合理,我希望有办法做到这一点 - 为什么不试试xml-dev邮件列表呢?最后我检查了它变得很吵,但xml的一些创造者仍然在那里闲逛。

答案 2 :(得分:0)

我有一个类似的问题:XML Schema Key with multiple fields

我认为对我来说最好的方法是重新排序XML以允许范围由地点确定,而不是强制使用两个字段的密钥。

在您的方案中,如果您在父级中移动referrer,则可以将范围设置为引用相应的子级。然后,您将使用referrer元素引用它需要引用的元素的外部范围。

确定这是否是可接受的解决方案有点困难,因为您的问题似乎有点抽象。在我的问题中,在我的问题中描述,我正在处理问题,答案和用户响应。我最初试图验证用户的响应是否真的是一个有效的答案;我的第一种方法涉及您使用的相同技术。我的最终解决方案是将响应移到问题内部,然后引用用户。

我的XML之前:

<?xml version="1.0" encoding="utf-8"?>
<survey>
  <user id="bob">
    <response questionIdRef="q101">yes</response>
    <response questionIdRef="q102">white</response>
  </user>
  <user id="jane">
    <response questionIdRef="q101">no</response>
    <response questionIdRef="q102">blue</response>
  </user>
  <question id="q101">
    <text>Do you like the color red?</text>
    <answer>yes</answer>
    <answer>no</answer>
  </question>
  <question id="q102">
    <text>What is your favorite color?</text>
    <answer>red</answer>
    <answer>blue</answer>
    <answer>white</answer>
    <answer>yellow</answer>
  </question>
</survey>

我的XML后:

<?xml version="1.0" encoding="utf-8"?>
<survey>
  <user id="bob" />
  <user id="jane" />
  <question id="q101">
    <text>Do you like the color red?</text>
    <answer>yes</answer>
    <answer>no</answer>
    <response userIdRef="bob">yes</response>
    <response userIdRef="jane">no</response>
  </question>
  <question id="q102">
    <text>What is your favorite color?</text>
    <answer>red</answer>
    <answer>blue</answer>
    <answer>white</answer>
    <answer>yellow</answer>
    <response userIdRef="bob">white</response>
    <response userIdRef="jane">blue</response>
  </question>
</survey>