【问题标题】:XSD key/keyref: hierarchical key structureXSD key/keyref:分层密钥结构
【发布时间】:2010-10-27 20:09:20
【问题描述】:

我正在尝试使用 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 仅在其包含的 parent 范围内是唯一的

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

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

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

然后我尝试定义一个复合键(在 root 上),使用:

  • 选择器 = 父级
  • 字段 = @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>

【问题讨论】:

  • 嗨 Aron,您找到解决此问题的方法了吗?我也遇到了类似的问题。(我无法更改我的 xml)。
  • 恐怕不会 - 我们最终转向了非 XML 格式进行数据交换,从而使问题变得毫无意义。

标签: xml schema xsd


【解决方案1】:

从孩子那里引用父母怎么样?即使有很多孩子,也只有一个父母,并且结合 (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

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

【讨论】:

  • 是的;我自己尝试过,并且对选择器和字段 xpath 表达式的严格限制做出了同样的发现。不过理论上是个好主意。感谢您的努力!
  • 我猜想结合这个约束,连同你找到的另一个约束(xpath 只引用一个节点),有证据表明你想做的事情在 XSD 中是不可能的 -我敢打赌,证明(如果有的话)很简单,但我看不太清楚。
【解决方案2】:

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

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

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

【讨论】:

  • 是的,这是可能的,但我认为它导致的问题多于解决的问题......正如你所说,丑陋。由于外部原因,我的设计已经脱离了这种结构,所以在这一点上它更像是一种学术练习,但也许我会试试这个列表。感谢您的想法!
【解决方案3】:

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

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

在您的场景中,如果您将引用者移动到父级内部,这将允许将范围设置为引用适当的子级。然后,您可以让引用者元素将外部范围引用到它需要引用的元素。

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

我之前的 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>

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 2011-01-02
    • 1970-01-01
    • 2013-04-06
    • 2012-03-27
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    相关资源
    最近更新 更多