如何在无命名空间的XSD中创建key/keyref XPath?
问题背景
尝试在XSD Schema中创建无命名空间的key/keyref XPath,以下代码无效(引用不存在的键未报错,XPath选择器/字段未被识别):
xmlns="http://mynamespace" <xsd:key name="myId"> <xsd:selector xpath="./AAA/a"/> <xsd:field xpath="@id"/> </xsd:key> <xsd:keyref name="myIdref" refer="myId"> <xsd:selector xpath="./BBB/b" /> <xsd:field xpath="@idref"/> </xsd:keyref>
尝试使用local-name()函数时,出现XPath子集不支持的错误:
<xsd:selector xpath="./*[local-name()='BBB']/*[local-name()='b']" />
错误信息:
c-general-xpath: The expression './[local-name()='BBB']/[local-name()='b']' is not valid with respect to the XPath subset supported by XML Schema.
目前仅当在XPath中为每个元素添加命名空间前缀时,key/keyref才能生效:
xmlns:p="http://mynamespace" <xsd:key name="myId"> <xsd:selector xpath="./p:AAA/p:a"/> <xsd:field xpath="@id"/> </xsd:key> <xsd:keyref name="myIdref" refer="p:myId"> <xsd:selector xpath="./p:BBB/p:b" /> <xsd:field xpath="@idref"/> </xsd:keyref>
疑问:这是唯一解决方案吗?如何创建无命名空间的key/keyref XPath?
解答
XML Schema的XPath子集限制
XML Schema对key/keyref中使用的XPath有严格的子集限制,不允许在谓词中使用local-name()这类函数,所以你用local-name()的写法必然报错,这是规范要求,没有绕过的办法。默认命名空间对XPath选择器不生效
XSD文档中声明的默认命名空间(xmlns="http://mynamespace")不会应用到XPath选择器中。XPath的默认命名空间默认是空的,所以直接写AAA/a会匹配无命名空间的<AAA>和<a>元素,而非你目标命名空间下的元素——这就是你最初的代码无效且无报错的原因:选择器根本没匹配到任何元素,自然不会触发键的校验逻辑。当前方案是标准且唯一可行的方式
如果你的目标元素属于某个命名空间(比如http://mynamespace),那么必须显式绑定命名空间前缀(如xmlns:p="http://mynamespace"),并在XPath选择器中使用该前缀来指定元素的命名空间。这是XML Schema规范中唯一支持的、能正确匹配命名空间元素的方式,不存在所谓的“无命名空间XPath”可以匹配命名空间内的元素。
只有当你的元素本身确实属于无命名空间时,才能直接使用不带前缀的XPath(如./AAA/a)来配置key/keyref。
内容的提问来源于stack exchange,提问作者Jian

