如何正确使用选择器xpath与扩展?

时间:2014-05-25 03:02:50

标签: xml xpath xsd

我有这样的事情:

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

第二
如何只在一组中访问扩展程序元素childChildAchildChildB的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

1 个答案:

答案 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中是不可能的。


关于架构中参考使用的说明:

如果要继续使用未加前缀的元素引用和类型(这是标准约定),则需要 xmlnsxmlns:tns声明。如果你不关心它们的前缀,你可以只保留前缀xmlns:tns,但你必须在所有类型和元素的引用前加上前缀,例如在<xs:element name="parentElement" type="tns:parentType">或{{1 }}。这是一种风格问题。