我有这样的事情:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://sample.domain.com/the/target/namespace"
xmlns:tns="http://sample.domain.com/the/target/namespace"
targetNamespace="http://sample.domain.com/the/target/namespace"
elementFormDefault="qualified">
<xs:element name="rootElement" type="rootType"/>
<xs:complexType name="rootType">
<xs:all>
<xs:element name="parentElement" type="parentType">
<xs:unique name="uniqueId">
<xs:selector xpath="tns:abstractElement"/> <!-- should access the abstractElement OR all extensions -->
<xs:field xpath="@id"/>
</xs:unique>
</xs:element>
</xs:all>
</xs:complexType>
<xs:complexType name="parentType">
<xs:choice maxOccurs="unbounded">
<xs:element name="childElementA" type="childTypeA"/>
<xs:element name="childElementB" type="childTypeB"/>
</xs:choice>
</xs:complexType>
<xs:element name="abstractElement" type="abstractType" abstract="true"/> <!-- how to access this element via xpath -->
<xs:complexType name="abstractType" abstract="true">
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
<xs:complexType name="childTypeA">
<xs:complexContent>
<xs:extension base="abstractType">
<xs:sequence>
<xs:element name="childChildA"> <!-- how to access this element via xpath in combination with 'childChildB' -->
<xs:complexType>
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="childTypeB">
<xs:complexContent>
<xs:extension base="abstractType">
<xs:sequence>
<xs:element name="childChildB"> <!-- how to access this element via xpath in combination with 'childChildA' -->
<xs:complexType>
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
和一个示例实例:
<?xml version="1.0" encoding="UTF-8"?>
<rootElement
xmlns="http://sample.domain.com/the/target/namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://sample.domain.com/the/target/namespace schema.xsd">
<parentElement>
<childElementA id="duplicate">
<childChildA id="foo"/>
</childElementA>
<childElementB id="duplicate">
<childChildB id="bar"/>
</childElementB>
</parentElement>
</rootElement>
第一
我想验证子元素的id属性是唯一的。在某些情况下xpath="*"
正在使用(见上文)
不起作用的是xpath="childElementA"
或xpath="abstractElement"
。
第二
如何只在一组中访问扩展程序元素childChildA
和childChildB
的ID?
另外
以这种方式一起使用扩展和xpath是好的还是坏的做法?
P.S。由于JAXB(Java XML Bindings),需要使用指定的complexType。
更新1
我还尝试了一个前缀为targetNamespace的选择器,例如xpath="xs:childElementA"
或xpath="xs:abstractElement"
。但它对我也没有用。
更新2
我将targetNamespace映射到前缀'tns'。我添加了一个示例实例,其中 childElementA 和 childElementB 的 id 相等。因此,它不应该验证。但确实如此:
$ xmllint --noout --schema schema.xsd schema-instance.xml
schema-instance.xml validates
答案 0 :(得分:1)
使用xs
前缀对类型进行前缀不起作用,因为您的类型不属于XML架构命名空间。它们属于您的targetNamespace
。
您需要将前缀映射到目标命名空间。它当前被声明为默认(xmlns
)命名空间,它允许您引用本地声明的类型和元素引用,而不必限定它们。但是,使用前缀显式限定的XPath选择器(在XSD 1.0 *中)将不会以相同的方式运行。未加前缀的选择器将始终被视为属于无命名空间。
要注册XPath可用的前缀/名称空间映射,只需为目标名称空间添加另一个名称空间声明,并将其与任何前缀(例如tns
)相关联:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://sample.domain.com/the/target/namespace"
xmlns:tns="http://sample.domain.com/the/target/namespace"
targetNamespace="http://sample.domain.com/the/target/namespace"
elementFormDefault="qualified"> ...
现在您可以在XPath选择器中使用它,它将在目标命名空间中找到元素:
<xs:unique name="uniqueId">
<xs:selector xpath="tns:abstractElement"/>
<xs:field xpath="@id"/>
</xs:unique>
*在XSD 1.1中,您可以声明xpathDefaultNamespace="##targetNamespace"
以允许XPath表达式将未加前缀的选择器视为属于目标命名空间,但这在XSD 1.0中是不可能的。
关于架构中参考使用的说明:
如果要继续使用未加前缀的元素引用和类型(这是标准约定),则需要 xmlns
和xmlns:tns
声明。如果你不关心它们的前缀,你可以只保留前缀xmlns:tns
,但你必须在所有类型和元素的引用前加上前缀,例如在<xs:element name="parentElement" type="tns:parentType">
或{{1 }}。这是一种风格问题。