gpt4 book ai didi

xml - 如何使用包含来自另一个命名空间的 keyref 的 XSD 创建 XML 实例

转载 作者:行者123 更新时间:2023-12-04 16:56:19 26 4
gpt4 key购买 nike

我正在尝试验证依赖于另一个实例(来自不同命名空间)的 XML 实例,并且它有一个指向该命名空间中的键的 keyref。当我尝试验证实例时,它会产生一个错误,指出 key 超出范围。

这些是我的 XSD:

test1.xsd

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

<xs:complexType name="Host">
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="hosts">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="host" type="Host"
/>
</xs:sequence>
</xs:complexType>
<xs:key name="Host-PK">
<xs:selector xpath="host"/>
<xs:field xpath="@id"/>
</xs:key>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>

test2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="test2" xmlns="test2" xmlns:t1="test1">

<xs:import namespace="test1" schemaLocation="test1.xsd"/>

<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="server">
<xs:complexType>
<xs:attribute name="host" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:keyref name="Host-FK" refer="t1:Host-PK">
<xs:selector xpath="server"/>
<xs:field xpath="@host"/>
</xs:keyref>
</xs:element>
</xs:schema>

我的实例:

test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test1 test1.xsd">
<hosts>
<host id="ABC"/>
<host id="DEF"/>
</hosts>
</root>

test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:t1="test1" xmlns="test2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test2 test2.xsd">
<server host="ABC"/>
</root>

服务器主机属性是对主机 ID 的关键引用。

在模式验证期间 test2.xml 文件引发了以下错误:

Error: [Xerces] Identity Constraint error: the keyref identity constraint "Host-FK" refers to a key or unique that is out of scope.



我该如何解决?

我该如何引用 test1.xml 来自 的实例test2.xml ?

最佳答案

我假设您可以更改两个 XSD,并且您使用的是 XSD 1.0。

在第一个 XSD 中,您需要限定 XPath 元素,因为未加前缀的元素不属于任何命名空间。因为你的 key 不起作用。您可以验证这一点,将重复的 ID 添加到 test1 :

<root xmlns="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test1 test1.xsd">
<hosts>
<host id="ABC"/>
<host id="DEF"/>
<host id="DEF"/>
</hosts>
</root>

它仍然验证,当它不应该。

要解决此问题,请添加第二个 test1带前缀的命名空间声明:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="test1" xmlns="test1" xmlns:t1="test1">

现在您可以限定您的 XPath 表达式:
<xs:key name="Host-PK">
<xs:selector xpath="t1:host"/>
<xs:field xpath="@id"/>
</xs:key>

正如预期的那样,对重复 ID 的验证将失败。

现在您的第二个 XSD 将无法找到任何 Host-PK .它的 root element 是完全不同的。它只是与 root 同名。的 test1 .它不可能在范围内。如果您想在两个模式中共享相同的 key ,您可以做的一件事就是声明 roottest2作为 root 的扩展在 test1 .但这将需要在 test1.xsd 中进行一些更改为了允许 test2引用 test1.xsd 中的元素和类型.

允许其他模式扩展 root 的类型元素,使其成为顶级。另外,制作 hosts元素顶层,因为我们需要引用它来定义 keyref .您还可以使用它来验证具有 hosts 的文件。作为根元素(这将很有用,我们将在前面看到)。

我们将无法扩展 xs:all ,但在您的情况下,您可以安全地将其替换为 xs:sequence .这是最后的 test1.xsd 重构后:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
elementFormDefault="qualified"
targetNamespace="test1"
xmlns="test1"
xmlns:t1="test1">

<xs:complexType name="Host">
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>

<xs:complexType name="Root">
<xs:sequence>
<xs:element ref="hosts" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:element name="root" type="Root" />

<xs:element name="hosts">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="host" type="Host"/>
</xs:sequence>
</xs:complexType>
<xs:key name="Host-PK">
<xs:selector xpath="t1:host"/>
<xs:field xpath="@id"/>
</xs:key>
</xs:element>

</xs:schema>

我还加了 minOccurs="0"hosts所以可以定义一个 root仅包含一个服务器(但这是暂时的 - 我们将在完成之前再次要求它)

现在我们可以引用 hosts元素和 Root输入 test2.xsd .我们可以从扩展 root 开始元素的基本类型,以允许 server元素:
<xs:complexType name="NewRoot">
<xs:complexContent>
<xs:extension base="t1:Root">
<xs:sequence>
<xs:element name="server">
<xs:complexType>
<xs:attribute name="host" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>

这也是一个序列。
root元素应声明为:
<xs:element name="root" type="NewRoot"> ... </xs:element>

现在 root test2 中的元素是 root 的扩展 test1 中的元素,以及 host元素将在上下文中。

由于我们必须使用XPath 来选择服务器元素,因此需要为 test2 的命名空间声明一个前缀。所以我们可以在 XPath 表达式中使用它:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:t1="test1" targetNamespace="test2"
xmlns="test2" xmlns:t2="test2" >

现在您可以定义一个引用 hosts/host 的本地 key 。并将其用于 host server 中的属性:
<xs:element name="root" type="t2:NewRoot">
<xs:key name="Host-PK">
<xs:selector xpath="t1:hosts/t1:host"/>
<xs:field xpath="@id"/>
</xs:key>
<xs:keyref name="Host-FK" refer="Host-PK">
<xs:selector xpath="t2:server"/>
<xs:field xpath="@host"/>
</xs:keyref>
</xs:element>

这是你最后的 test2.xsd 重构后:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
elementFormDefault="qualified"
targetNamespace="test2"
xmlns="test2"
xmlns:t2="test2"
xmlns:t1="test1">

<xs:import namespace="test1" schemaLocation="test1.xsd"/>

<xs:complexType name="NewRoot">
<xs:complexContent>
<xs:extension base="t1:Root">
<xs:sequence>
<xs:element name="server">
<xs:complexType>
<xs:attribute name="host" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>

<xs:element name="root" type="t2:NewRoot">
<xs:key name="Host-PK">
<xs:selector xpath="t1:hosts/t1:host"/>
<xs:field xpath="@id"/>
</xs:key>
<xs:keyref name="Host-FK" refer="Host-PK">
<xs:selector xpath="t2:server"/>
<xs:field xpath="@host"/>
</xs:keyref>
</xs:element>
</xs:schema>

所以现在你尝试验证 test2.xml并且......它失败了,但不再出现“超出范围”的错误。它失败了,因为它没有找到任何带有 ABC 的 key 值(value)。这意味着它正在验证 key ,但它无法访问 host元素。您需要在 XML 实例中包含它们。

如果您简单地剪切和粘贴 hosts 它将起作用来自 test1.xml 的元素并为它们设置默认命名空间:
<root xmlns:t1="test1" xmlns="test2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test2 test2.xsd">
<hosts xmlns="test1">
<host id="ABC"/>
<host id="DEF"/>
</hosts>
<server host="ABC"/>
</root>

你可以试试看。除非 host 否则它不会验证是 ABCDEF .

您可能还想保留 hosts子树在一个单独的文件中,并将其导入到您的两个 XML 实例中。这样做的 native 方法是声明一个 DTD 实体。首先放置您的 hosts在文件中( test3.xml ):
<hosts xmlns="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="test1 test1.xsd">
<host id="ABC"/>
<host id="DEF"/>
</hosts>

现在将它包含在 test1.xml 中和 test2.xml使用 <!ENTITY> :

test1.xml
<!DOCTYPE root [
<!ENTITY test3 SYSTEM "test3.xml">
]>

<root xmlns="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test1 test1.xsd">
&test3;
</root>

test2.xml
<!DOCTYPE root [
<!ENTITY test3 SYSTEM "test3.xml">
]>

<root xmlns:t1="test1" xmlns="test2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test2 test2.xsd">
&test3;
<server host="ABC"/>
</root>

现在您可以放置​​ minOccurs="0"返回 hosts 的声明在 test1.xsd ,以保证它始终存在。

关于xml - 如何使用包含来自另一个命名空间的 keyref 的 XSD 创建 XML 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23225613/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com