将 fn:data 应用于信息节点时的奇怪行为

Strange behaviour when applying fn:data to info-node

当我在 MarkLogic 中 运行 以下 xquery":

xquery version "1.0-ml";

let $envelope := <envelope xmlns="http://marklogic.com/entity-services"> 
                                <info>hello</info>
                             </envelope>

return fn:data($envelope/es:info)

我收到此错误:

[1.0-ml] XDMP-NONMIXEDCOMPLEXCONT: fn:data(hello) -- 节点具有非混合复杂内容的复杂类型

奇怪的是,当我将信息节点重命名为 info1 时,代码按预期工作:

xquery version "1.0-ml";

let $envelope := <envelope xmlns="http://marklogic.com/entity-services">
                         <info1>hello</info1>
                     </envelope>

return fn:data($envelope/es:info1)

结果是:你好(如预期)

谁能给我解释一下这个黑魔法?

我想这是因为架构 entity-type.xsd 将元素定义为非混合:

<xs:complexType name="InfoType">
    <xs:sequence>
      <xs:element ref="es:title"/>
      <xs:element ref="es:version"/>
      <xs:element ref="es:base-uri" minOccurs="0"/>
      <xs:element ref="es:description" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

<xs:element name="info" type="es:InfoType"/>

如果元素具有 mixed="true" 属性,则它可以是混合内容。因为在这种情况下您无法更改模式,所以我会尝试使用 string().

declare namespace es = "http://marklogic.com/entity-services";

let $envelope := <envelope xmlns="http://marklogic.com/entity-services"> 
                    <info>
                      <title>hello</title>
                      <version>1.0</version>
                    </info>
                 </envelope>

return $envelope/es:info/string()

如果这是您想要的结果,这会给您 hello1.0

您使用 info1 的示例有效,因为此元素未在架构中定义(因此不会是有效的 xml)。

因为 fn:data() 与模式有潜在的交互作用,请考虑使用 fn:string() 将元素的文本作为字符串获取。

MarkLogic 在使用 fn:data() 时会尝试从您的数据中检索键入的值。 MarkLogic 将为此目的寻找合适的模式。由于您使用的是实体服务命名空间,因此它将查找实体服务模式。此架构对 info 元素有特定定义(正如 Michael 正确提到的那样),这与您使用它的方式不匹配。

使用 fn:string() 而不是 fn:data() 通常更可靠,因为它将绕过数据类型检查。使用未在实体服务模式中定义的元素名称可以为您提供一个现在可以使用的快速修复,但要保证它在将来也可以使用可能会很棘手。

就我个人而言,我建议按预期使用实体服务命名空间。如果您需要放入额外的元素,将它们放在不同的命名空间中,有或没有伴随的模式。或者,完全删除命名空间。

HTH!