【问题标题】:Using global map variable with BaseX collection将全局映射变量与 BaseX 集合一起使用
【发布时间】:2020-05-11 06:38:51
【问题描述】:

我正在使用 BaseX (v9.3.2) XQuery v3.1。我有一个 XQuery 脚本,用于评估 BaseX 集合中的所有 XML 文件。该集合有大约 100 个文件,每个文件的大小在 30MB 到 1.5GB 之间,并且具有相同的 XSD 架构。为了获得更好的性能,脚本使用 BaseX Map Module 将键映射到值并通过键快速获取值。我已经声明了几个map(*) 类型的模块全局变量。关键是键值仅在 one XML 文件中是唯一的。为了使密钥在整个集合中唯一,我只是添加了base-uri($value),'_' 作为密钥的附加部分:)。它工作正常。我看到的主要缺点是需要通过所有连续的函数调用FooN($baseuri, $arg2) FooN-1($baseuri, $arg2) ... Foo1($baseuri, $arg2)隧道base-uri,即使$baseuri 值是在第一次调用FooN($baseuri, $arg2) 时设置的,但仅用于执行链的最后一个函数。为了更清楚,请参阅下面的 XQuery 代码。这里 $basuri 最后只在 helper:Foo1 中需要,但我们也需要在 helper:Foo2 中将其作为参数传递。

我的问题是关于参数隧道是否有更好的方法并且没有其他缺点(性能、内存)。

XQuery 代码

xquery version "3.1" encoding "utf-8";

declare namespace helper="helperns";

declare variable $helper:root := db:open("BMW");

declare variable $helper:mapAS_ApplicationRecordElementByTypeRef as map(*) := map:merge(for $value in $helper:root//*:APPLICATION-RECORD-ELEMENT[*:TYPE-TREF/@DEST='APPLICATION-PRIMITIVE-DATA-TYPE'] return map:entry(concat(base-uri($value),'_',$value/*:TYPE-TREF/tokenize(text(),'/')[last()]), $value));
declare variable $helper:mapAS_ImplementationDataTypeRefByApplicationDatatypeRef as map(*) := ...


...

declare function helper:Foo1($applPrimitiveDataType as element(),$basuri as xs:string)
as element() {
  let $applRecordElement := map:get($helper:mapAS_ApplicationRecordElementByTypeRef, concat($basuri,'_',$applPrimitiveDataType/*:SHORT-NAME/text()))
...
  let $resolved := if($implDataTypeElement) then (
...
    )
    else (
      <RESOLVED_DATATYPE>
        <SHORT-NAME resolveinfo='not resolved (DB ERROR)'>unknown</SHORT-NAME>
      </RESOLVED_DATATYPE>  
    )
  return ($resolved)
};

...

declare function helper:Foo2($basuri as xs:string)
as element()* {
  let $applicationPrimitiveDataTypes := ...
  let $res :=
    for $applicationPrimitiveDataType in $applicationPrimitiveDataTypes
...
      order by $shortname
      return (
        if (not($implDataTypeRef)) then (
          let $dataTypeResolved := helper:Foo1($applicationPrimitiveDataType,$basuri)
          return(
            <MAPPING appldtname="{$shortname}" size="{$dataTypeResolved/*:SHORT-NAME/@size}" basedatatype="{$dataTypeResolved/*:SHORT-NAME}" resolveinfo="{$dataTypeResolved/SHORT-NAME/@resolveinfo}"/>
          )
        )
      )
  return($res)
};


let $mappingsForAllDocs :=
  for $doc in helper:getAllDocs()/doc
...
    let $missingmappings := helper:Foo2($doc/@baseuri)
    return (
      <FILE name="{$doc/@filename}" missing="{count($missingmappings)}">
        <MISSING-MAPPING>{$missingmappings}</MISSING-MAPPING>
...
      </FILE>
    )

let $allDocs :=
  for $doc in helper:getAllDocs()/doc
    order by $doc/@filename
    return (
      <FILE name="{$doc/@filename}"/>
    )

return($mappingsForAllDocs)

【问题讨论】:

    标签: xml xquery basex xquery-3.0


    【解决方案1】:

    您是否考虑过使用唯一 ID 更新 XML 文件(或生成新文件集)?一旦有了唯一的 ID,像 BaseX 这样的 XML 数据库就能够使用 fn:id() 函数进行快速查找。如需更新 XML 文件,请参阅 https://docs.basex.org/wiki/XQuery_Update。

    【讨论】:

    • 谢谢,这看起来是一个很好的实用方法,我会探索它。我希望 XQuery 中的语法支持类似于 XSLT v2 中带有参数的隧道功能。
    • 我已经更新了集合,并使各自的 /path//to/the/@ID 独一无二:for $id in /path//to/the/@ID return replace value of node $id with concat(base-uri($id),'_',$id)。撤消也可以正常工作:for $id in /path//to/the/@ID return replace value of node $id with replace($id,concat(base-uri($id),"_"),'').
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 2019-07-26
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多