Module XQuery:跨(导入的)模块共享全局变量

Module XQuery:跨(导入的)模块共享全局变量,module,global-variables,xquery,Module,Global Variables,Xquery,令我惊讶的是,我正在努力解决一个非常基本的XQuery问题,即在主XQuery模块和导入的库模块之间共享全局变量的正确方法是什么。简单地说,我想在某个地方定义一个可以在任何地方重用的全局变量,即在所有导入的XQuery模块中,我正在努力找到声明这样一个变量的最佳位置 假设我有以下主要的XQuery test.xq: import module namespace global="global" at "global.xq"; import module namespace test2="test

令我惊讶的是,我正在努力解决一个非常基本的XQuery问题,即在主XQuery模块和导入的库模块之间共享全局变量的正确方法是什么。简单地说,我想在某个地方定义一个可以在任何地方重用的全局变量,即在所有导入的XQuery模块中,我正在努力找到声明这样一个变量的最佳位置

假设我有以下主要的XQuery test.xq:

import module namespace global="global" at "global.xq";
import module namespace test2="test2" at "test2.xq";

declare variable $test := 'test!';

test2:echo()
此模块导入以下库模块:

global.xq:

module namespace global="global";

declare variable $global:test := 'global!';
test2.xq: 模块名称空间test2=test2

import module namespace global="global" at "global.xq";

declare function test2:echo() {
  $global:test
};
这是可行的,但给我留下了一些问题:

是这样做的吗:

定义全局变量,例如$global:在单独的库模块(例如global.xq)中进行测试 在需要的地方导入该模块,以提供对其变量的访问 ?

是否有方法访问主XQuery模块中声明的变量,例如导入的库模块(例如test2.xq)中的$test? 有人能解释一下吗?我想我发现自己在这个概念上挣扎的主要原因是因为我习惯了男人的行为,这可能比它应该做的要宽松。在eXist中,test2.xq模块可以只引用$global:test变量,而不导入global.xq模块:

module namespace test2="test2";
declare namespace global="global";

declare function test2:echo() {
  $global:test
};
由于这在eXist中有效,但在Saxon中不起作用,我开始想知道在导入的XQuery模块中定义和使用全局变量的正确方法是什么

亲切问候,


Ron

显然采用了您可能熟悉的XSLT方法。在这里,您还可以通过包含/导入链中较高的“祖先”模块的导入/包含来引用在当前模块之外声明的变量和参数

据我所知,这不符合XQuery标准

显然,能够使用它是非常实际的,但是有一些很好的理由不这样做。理想情况下,模块是自包含的、可重用的组件,当它们依赖于这样的外部参数/变量时,情况就不再是这样了。最好将上下文信息作为参数传递给这些函数。看起来并不总是优雅的,但最终是更好的设计


一些实现提供了使用变量值重新定义的替代选项。MarkLogic有xdmp:set命令,我相信saxon也有变量赋值,或者在XSLT?中是这样的?。您可以使用它来“初始化”模块。请注意,模块不是对象,因此请尽量避免使用这种方法来保存状态完整的信息。这也意味着您将依赖于特定于实现的功能。除非你能用这个更新工具。虽然不确定是否打算这样做,..

显然存在,但采用了您可能熟悉的XSLT方法。在这里,您还可以通过导入/导入链中较高级别的“祖先”模块的导入/包含来引用在当前模块外声明的变量和参数

据我所知,这不符合XQuery标准

显然,能够使用它是非常实际的,但是有一些很好的理由不这样做。理想情况下,模块是自包含的、可重用的组件,当它们依赖于这样的外部参数/变量时,情况就不再是这样了。最好将上下文信息作为参数传递给这些函数。看起来并不总是优雅的,但最终是更好的设计

一些实现提供了使用变量值重新定义的替代选项。MarkLogic有xdmp:set命令,我相信saxon也有变量赋值,或者在XSLT?中是这样的?。您可以使用它来“初始化”模块。请注意,模块不是对象,因此请尽量避免使用这种方法来保存状态完整的信息。这也意味着您将依赖于特定于实现的功能。除非你能用这个更新工具。但是,不确定它是否打算以这种方式工作。

在您的实际用例中,这些变量是什么?顾名思义,它们是否需要能够变化?如果是这样的话,将它们放在文档中可能是正确的做法。如果它们只是常量,那么您给出的方法——将它们放在单个模块/命名空间中,并根据需要导入它们——可能是正确的

坦率地说,编写模块时假设其他地方定义了某些东西,但没有定义其他地方应该在哪里,这让我觉得很容易发生危险——如果没有其他原因的话,这会让读者更难遵循控制流。因此,我有点不清楚为什么这种行为是可取的

考虑将配置封装在文档中,并将该文档作为参数传递给函数调用。

在实际用例中,这些变量是什么?顾名思义,它们是否需要能够变化?如果是这样的话,将它们放在文档中可能是正确的做法。如果它们只是常数,那么方法 您给出的—将它们放在单个模块/名称空间中,并根据需要导入—可能是正确的

坦率地说,编写模块时假设其他地方定义了某些东西,但没有定义其他地方应该在哪里,这让我觉得很容易发生危险——如果没有其他原因的话,这会让读者更难遵循控制流。因此,我有点不清楚为什么这种行为是可取的


考虑将配置封装在文档中,并将该文档作为参数传递给函数调用。

谢谢您的想法。我很清楚,我可能会碰到基于非标准行为的假设。然而,我在网上找不到很多关于这种设计模式的有用提示。我不喜欢为这种基本需求提供特定于供应商的扩展。您是否会推荐我原始问题中的工作方法,即在专用库模块中定义全局变量,并根据需要导入,作为所有导入XQuery模块都可以访问全局变量的标准方法?或者你看到了其他一致的可能性吗?@rvdb我建议通过参数将这些值传递给每个调用。将大量上下文信息收集到一个小的XML片段中,并将其传递是非常容易的。它是迄今为止最可扩展和最干净的。像您这样导入一个共享的globals模块是最明智的选择,除非您有充分的理由想要我描述的那种初始化行为。。嗯!谢谢你的想法。我很清楚,我可能会碰到基于非标准行为的假设。然而,我在网上找不到很多关于这种设计模式的有用提示。我不喜欢为这种基本需求提供特定于供应商的扩展。您是否会推荐我原始问题中的工作方法,即在专用库模块中定义全局变量,并根据需要导入,作为所有导入XQuery模块都可以访问全局变量的标准方法?或者你看到了其他一致的可能性吗?@rvdb我建议通过参数将这些值传递给每个调用。将大量上下文信息收集到一个小的XML片段中,并将其传递是非常容易的。它是迄今为止最可扩展和最干净的。像您这样导入一个共享的globals模块是最明智的选择,除非您有充分的理由想要我描述的那种初始化行为。。嗯!不,它们是常数;我更多考虑的是一个配置文件,其中包含可由通用代码使用的特定于应用程序的值。通用代码可以用于不同的应用程序,每个应用程序都有自己的配置值。我猜你的第二句话与我提到的行为有关?在这种情况下,我同意:我宁愿选择符合规范的路线。@rvdb-ah,明白了。我个人输入配置值的方法是通过配置文档注入配置值,作为参数传递给任何需要这些值的调用。现在,我将此文档作为上下文参数传递给实际调用,而不是将其存储在数据库中,尽管我不确定这种特定的方法是否适合长期使用。。。但无论哪种方式,显式都比隐式好。@rvdb…事实上,看起来grtjn独立地提出了相同的方法;我将此解读为对我自己使用的某种程度的辩护/验证:查尔斯和@grtjn:非常感谢您的有益见解!虽然我愿意接受你的两个答案,但我还是要应用第一个答案的规则。谢谢,伙计们。不,它们是常数;我更多考虑的是一个配置文件,其中包含可由通用代码使用的特定于应用程序的值。通用代码可以用于不同的应用程序,每个应用程序都有自己的配置值。我猜你的第二句话与我提到的行为有关?在这种情况下,我同意:我宁愿选择符合规范的路线。@rvdb-ah,明白了。我个人输入配置值的方法是通过配置文档注入配置值,作为参数传递给任何需要这些值的调用。现在,我将此文档作为上下文参数传递给实际调用,而不是将其存储在数据库中,尽管我不确定这种特定的方法是否适合长期使用。。。但无论哪种方式,显式都比隐式好。@rvdb…事实上,看起来grtjn独立地提出了相同的方法;我将此解读为对我自己使用的某种程度的辩护/验证:查尔斯和@grtjn:非常感谢您的有益见解!虽然我愿意接受你的两个答案,但我还是要应用第一个答案的规则。谢谢,伙计们。