XQuery:如何使用计算命名空间构造函数设置默认命名空间?

时间:2015-08-21 05:31:36

标签: xquery saxon basex

使用直接元素构造函数设置默认命名空间非常简单。例如:

<map xmlns="http://www.w3.org/2013/XSL/json"/>

上述直接构造函数按预期输出完全相同的元素。但是,如果我尝试对计算元素和命名空间构造函数做同样的事情,那我就不幸了:

element {"map"} {
  namespace {""} { "http://www.w3.org/2013/XSL/json" }
}

以上内容在BaseX 8.2中引发Duplicate namespace declaration: ''错误;和Saxon-HE 9.6中的XTDE0440: Cannot output a namespace node for the default namespace when the element is in no namespace

如果我传递前缀,那就没问题了。以下效果很好:

element {"map"} {
  namespace { "e" } {"http://www.w3.org/2013/XSL/json"}
}

在上述情况下,BaseX和Saxon都没有抱怨。但我想将命名空间设置为默认命名空间。

关于计算名称空间构造函数,XQuery 3.0规范says

  

如果构造函数指定了PrefixExpr,则前缀表达式的计算方法如下:

     

湾如果结果是空序列或零长度xs:string 或xs:untypedAtomic值,则新命名空间节点没有名称(此类命名空间节点表示默认命名空间的绑定)。

该规范还提供了一个类似的&#34;计算名称空间构造函数示例,其前缀为空白&#34;:

namespace { "" } {"http://a.example.com" }

为什么然后,错误消息?显然,计算的命名空间构造函数尝试重新声明已由计算元素构造函数声明的命名空间。另一方面,直接构造函数将直接初始化元素的命名空间到我的选择。但这只是我的猜测。我唯一确定的是我的困惑。

在任何情况下,有没有办法用计算构造函数获得直接构造函数可以实现的相同结果?

3 个答案:

答案 0 :(得分:5)

基本原因是元素的名称(即名称的前缀,本地和uri部分)由元素构造函数本身决定,而不是由添加到元素的动态内容决定。

执行此操作时:

element {"map"} {
  namespace {""} { "http://www.w3.org/2013/XSL/json" }
}

您正在创建一个没有前缀且没有命名空间的元素,然后您将为它提供一个命名空间节点,该节点将默认命名空间绑定到&#34; no namespace&#34 ;;你不可能两种方式。动态添加命名空间到元素的内容永远不会改变元素名称。

答案 1 :(得分:2)

我没有在saxon或basex中测试过这个,但是在Marklogic中使用XQuery3,这可行:

element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} { }

但是,仅此一点可能实际上并不能达到你想要的效果。

在XQuery中,计算构造函数不从父元素继承默认名称空间;第一部分始终是元素的(完全限定的)QName。你可以在那里使用一个字符串,但它被强制转换为QName - 如果该字符串没有前缀,那么你明确要求一个带有 no 命名空间的元素(除非你已经声明了一个默认的元素命名空间) ,在这种情况下,你要求的是)。这意味着即使您在元素上设置了默认命名空间,任何未在构造函数中指定默认命名空间的子节点都会将其显式设置为“”。

到目前为止,使用计算构造函数的最简单方法是在文件顶部声明命名空间,然后在每个元素名称上使用前缀。这确实导致XML在每个元素上都带有前缀。就个人而言,我喜欢明显无疑是多么明确,但很多人发现它过于冗长,特别是在只使用一个命名空间的XML中。

你也可以使用我上面使用的构造用于每个元素,它们或多或少会做同样的事情,但不使用前缀。如果你这样做,你必须在你的代码中构造它的每个元素上指定名称空间,结果XML 应该只在顶级元素上指定它,子元素继承它就像你一样我希望(虽然这可能取决于你的XQuery处理器。)

或者,您可以声明默认元素名称空间,然后仅为不同的元素指定名称空间。就个人而言,我觉得这很容易让人难以发现错误。

答案 2 :(得分:0)

我尝试添加评论,但不会让我放入换行符。

作为答案中提到的Will Goring,子元素不会从父级继承默认命名空间。使这更容易的一种方法是声明命名空间并在子元素中使用它。

declare namespace json = "http://www.w3.org/2013/XSL/json";

element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} {
    element json:child { }
}

变为

<map xmlns="http://www.w3.org/2013/XSL/json"><child/></map>

其中child具有相同的默认命名空间。

相当于:

element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} {
    element {fn:QName("http://www.w3.org/2013/XSL/json", "child")} { }
}