XQuery:如何使用计算的命名空间构造函数设置默认命名空间?
XQuery: How to set default namespace with a computed namespace constructor?
使用直接元素构造函数设置默认名称空间非常简单。例如:
<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:
If the constructor specifies a PrefixExpr, the prefix expression is evaluated as follows:
b. If the result is the empty sequence or a zero-length xs:string or xs:untypedAtomic value, the new namespace node has no name (such a namespace node represents a binding for the default namespace).
该规范还提供了“具有空前缀的计算命名空间构造函数”的类似示例:
namespace { "" } {"http://a.example.com" }
为什么会出现错误消息?显然,计算的命名空间构造函数试图重新声明已由计算元素构造函数声明的命名空间。另一方面,直接构造函数将根据我的选择直接初始化元素的名称空间。但这只是我的猜测。我唯一确定的是我的困惑。
无论如何,有没有办法用计算构造函数获得与直接构造函数可实现的相同结果?
我没有在 saxon 或 basex 中测试过这个,但是在 Marklogic 中使用 XQuery3,这有效:
element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} { }
但是,仅此一项可能无法真正满足您的需求。
在 XQuery 中,计算构造函数不从父元素继承默认名称空间;第一部分始终是元素的(完全限定的)QName。你可以在那里使用一个字符串,但它被强制转换成一个 QName - 如果该字符串没有前缀那么你明确要求一个带有 no 命名空间的元素(除非你已经声明了一个默认元素命名空间,在这种情况下,您需要它)。这意味着即使您在元素上设置了默认命名空间,您未在构造函数中为其指定默认命名空间的任何子元素也会显式将其设置回“”。
到目前为止,使用计算构造函数的最简单方法是在文件顶部声明名称空间,然后在每个元素名称上使用前缀。这确实会导致 XML 每个元素都有前缀。就个人而言,我喜欢它的明确性,但很多人觉得它过于冗长,尤其是在 XML 中,它只使用一个命名空间。
您还可以对每个元素使用我上面使用的构造,这将或多或少地做同样的事情,但不使用前缀。如果这样做,虽然您必须在代码中构造它的每个元素上指定名称空间,但结果 XML 应该 只在顶级元素上指定它,子元素像您期望的那样继承它(尽管这可能取决于您的 XQuery 处理器。)
或者,您可以声明默认元素命名空间,然后只为与此不同的元素指定一个命名空间。不过,就个人而言,我发现这令人困惑并且容易发现错误。
基本原因是元素的名称(即名称的前缀、局部和uri部分)是由元素构造器本身决定的,而不是由添加到元素中的动态内容决定的元素.
当你这样做时:
element {"map"} {
namespace {""} { "http://www.w3.org/2013/XSL/json" }
}
您正在创建一个没有前缀和命名空间的元素,然后给它一个命名空间节点,该节点将默认命名空间绑定到 "no namespace" 以外的其他内容;你不能两者兼得。向元素的内容动态添加命名空间永远不会更改元素名称。
我尝试添加评论,但不允许我输入换行符。
正如 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>
其中子项具有相同的默认命名空间。
相当于:
element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} {
element {fn:QName("http://www.w3.org/2013/XSL/json", "child")} { }
}
使用直接元素构造函数设置默认名称空间非常简单。例如:
<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:
If the constructor specifies a PrefixExpr, the prefix expression is evaluated as follows:
b. If the result is the empty sequence or a zero-length xs:string or xs:untypedAtomic value, the new namespace node has no name (such a namespace node represents a binding for the default namespace).
该规范还提供了“具有空前缀的计算命名空间构造函数”的类似示例:
namespace { "" } {"http://a.example.com" }
为什么会出现错误消息?显然,计算的命名空间构造函数试图重新声明已由计算元素构造函数声明的命名空间。另一方面,直接构造函数将根据我的选择直接初始化元素的名称空间。但这只是我的猜测。我唯一确定的是我的困惑。
无论如何,有没有办法用计算构造函数获得与直接构造函数可实现的相同结果?
我没有在 saxon 或 basex 中测试过这个,但是在 Marklogic 中使用 XQuery3,这有效:
element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} { }
但是,仅此一项可能无法真正满足您的需求。
在 XQuery 中,计算构造函数不从父元素继承默认名称空间;第一部分始终是元素的(完全限定的)QName。你可以在那里使用一个字符串,但它被强制转换成一个 QName - 如果该字符串没有前缀那么你明确要求一个带有 no 命名空间的元素(除非你已经声明了一个默认元素命名空间,在这种情况下,您需要它)。这意味着即使您在元素上设置了默认命名空间,您未在构造函数中为其指定默认命名空间的任何子元素也会显式将其设置回“”。
到目前为止,使用计算构造函数的最简单方法是在文件顶部声明名称空间,然后在每个元素名称上使用前缀。这确实会导致 XML 每个元素都有前缀。就个人而言,我喜欢它的明确性,但很多人觉得它过于冗长,尤其是在 XML 中,它只使用一个命名空间。
您还可以对每个元素使用我上面使用的构造,这将或多或少地做同样的事情,但不使用前缀。如果这样做,虽然您必须在代码中构造它的每个元素上指定名称空间,但结果 XML 应该 只在顶级元素上指定它,子元素像您期望的那样继承它(尽管这可能取决于您的 XQuery 处理器。)
或者,您可以声明默认元素命名空间,然后只为与此不同的元素指定一个命名空间。不过,就个人而言,我发现这令人困惑并且容易发现错误。
基本原因是元素的名称(即名称的前缀、局部和uri部分)是由元素构造器本身决定的,而不是由添加到元素中的动态内容决定的元素.
当你这样做时:
element {"map"} {
namespace {""} { "http://www.w3.org/2013/XSL/json" }
}
您正在创建一个没有前缀和命名空间的元素,然后给它一个命名空间节点,该节点将默认命名空间绑定到 "no namespace" 以外的其他内容;你不能两者兼得。向元素的内容动态添加命名空间永远不会更改元素名称。
我尝试添加评论,但不允许我输入换行符。
正如 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>
其中子项具有相同的默认命名空间。
相当于:
element {fn:QName("http://www.w3.org/2013/XSL/json", "map")} {
element {fn:QName("http://www.w3.org/2013/XSL/json", "child")} { }
}