搜索​​​​

清除过滤器
文章
姚 鑫 · 七月 2, 2021

第二十五章 添加和使用XSLT扩展函数

# 第二十五章 添加和使用XSLT扩展函数 # 自定义错误处理 当出现错误时,XSLT处理器(`Xalan`或`Saxon`)执行当前错误处理程序的`error()`方法,将消息作为参数发送到该方法。类似地,当发生致命错误或警告时,XSLT处理器会根据需要执行`datalError()`或`Warning()`方法。 对于所有这三种方法,默认行为是将消息写入当前设备。 要自定义错误处理,请执行以下操作: - 对于`Xalan`或`Saxon`处理器,在创建`%XML.XSLT.ErrorHandler`的子类。在这个子类中,根据需要实现`Error()`、`FatealError()`和`Warning()`方法。 这些方法中的每一个都接受单个参数,即包含由XSLT处理器发送的消息的字符串。 这些方法不返回值。 - 要在编译样式表时使用此错误处理程序,请创建子类的实例,并在编译样式表时在参数列表中使用它。 - 若要在执行XSLT转换时使用此错误处理程序,请创建子类的实例,并在使用的`Transform`方法的参数列表中使用它。 # 指定样式表使用的参数 要指定样式表使用的参数,请执行以下操作: 1. 创建`%ArrayOfDataTypes`的实例在。 2. 调用此实例的`SetAt()`方法将参数及其值添加到此实例。对于`SetAt()`,将第一个参数指定为参数值,将第二个参数指定为参数名称。 根据需要添加任意多个参数。 ```java Set tParameters=##class(%ArrayOfDataTypes).%New() Set tSC=tParameters.SetAt(1,"myparameter") Set tSC=tParameters.SetAt(2,"anotherparameter") ``` 3. 将此实例用作`Transform`方法的`pParms`参数。 可以不使用`%ArrayOfDataType`,而是使用 IRIS多维数组,该数组可以具有任意数量的具有以下结构和值的节点: Node| Value ---|--- arrayname("parameter_name") |Value of the parameter named by parameter_name # 添加和使用XSLT扩展函数 可以在InterSystems IRIS中创建`XSLT`扩展函数,然后在样式表中使用它们,如下所示: - 对于`XSLT2.0`(`Saxon`处理器),可以使用名称空间`com.intersystems.xsltgateway.XSLTGateway`中的`evaluate`函数或名称空间`http://extension-functions.intersystems.com`中的`evaluate`函数 - 对于`XSLT1.0`(`Xalan`处理器),只能在名称空间`http://extension-functions.intersystems.com`中使用`evaluate`函数 默认情况下(举个例子),后一个函数反转它接收到的字符。但是,通常不使用默认行为,因为实现了一些其他行为。要模拟多个单独的函数,需要传递一个选择器作为第一个参数,并实现一个开关,该开关使用该值选择要执行的处理。 在内部,`evaluate`函数作为XSLT回调处理程序中的方法(`evaluate()`)实现。 要添加和使用XSLT扩展函数,请执行以下操作: 1. 对于`Xalan`或`Saxon`处理器,在创建`%XML.XSLT.CallbackHandler`的子类。在这个子类中,根据需要实现`evaluate()`方法。请参阅下一小节。 2. 在样式表中,声明`evaluate`函数所属的命名空间,并根据需要使用`evaluate`函数。请参阅下一小节。 3. 执行XSLT转换时,创建子类的实例,并在使用的`Transform`方法的参数列表中使用它。请参阅“执行XSLT转换”。 ## 实现evaluate()方法 在内部,调用`XSLT`处理器的代码可以将任意数量的位置参数传递给当前回调处理程序的`evaluate()`方法,该方法将它们作为具有以下结构的数组接收: Node| Value ---|--- Args| 参数数量 Args(index) |位置索引中参数的值 该方法只有一个返回值。返回值可以是: - 标量变量(如字符串或数字)。 - 流对象。这允许返回超过字符串长度限制的超长字符串。流必须包装在新窗口中的`%XML.XSLT.StreamAdapter`实例中,使XSLT处理器能够读取流。以下是部分示例: ```java Method evaluate(Args...) As %String { //create stream ///... // create instance of %XML.XSLT.StreamAdapter to // contain the stream Set return=##class(%XML.XSLT.StreamAdapter).%New(tStream) Quit return } ``` ## 在样式表中使用计算 要在XSLT中使用XSLT扩展函数,必须在XSLT样式表中声明扩展函数的名称空间。对于InterSystems evaluate函数,此命名空间是`http://extension-functions.intersystems.com`或`com.intersystems.xsltgateway.XSLTGateway`,如前所述。 下面的示例显示使用evaluate的样式表: ```xml ``` ## 使用ISC:计算缓存 XSLT2.0网关将`evaluate`函数调用缓存在`isc:evaluate`缓存中。缓存的默认最大大小为`1000`个项目,但可以将大小设置为不同的值。此外,还可以清除缓存、转储缓存,还可以从`%List`中预先填充缓存。使用以下格式: - 缓存条目总数 - 对于每个条目: 1. 求值参数总数 2. 所有求值参数 3. 计算值 缓存还包括可缓存的函数名称的过滤器列表。请注意以下事项: - 可以在筛选器列表中添加或删除函数名。 - 可以清除过滤器列表。 - 可以通过设置一个布尔值来覆盖筛选器列表,该布尔值将缓存每个`evaluate`调用。 将函数名添加到筛选器列表不会限制求值缓存的大小。可以对同一函数进行任意数量的调用,但具有不同的参数和返回值。函数名和参数的每个组合都是求值缓存中的一个单独条目。 可以使用`%XML.XSLT2.Transformer`中的方法来操作求值缓存。 # 使用XSL转换向导 Studio提供了一个执行XSLT转换的向导,当希望快速测试样式表或自定义XSLT扩展函数时,该向导非常有用。要使用此架构向导,请执行以下操作: 1. Tools > Add-Ins > XSLT Schema Wizard. 2. 指定以下必需的详细信息: - 对于XML文件,选择浏览以选择要转换的XML文件。 - 对于XSL文件,选择浏览以选择要使用的XSL样式表。 - 对于呈现为,选择文本或XML以控制转换的显示方式。 3. 如果已在要在此转换中使用的创建了`%XML.XSLT.CallbackHandler`的子类,请指定以下详细信息: - 对于XSLT Helper Class中的第一个下拉列表,选择一个命名空间。 - 对于XSLT Helper Class中的第二个下拉列表,选择该类。 4. 选择Finish(完成)。 对话框底部显示转换后的文件。可以从该区域复制和粘贴。 5. 要关闭此对话框,请选择取消。
文章
姚 鑫 · 七月 1, 2021

第二十四章 执行XSLT转换

# 第二十四章 执行XSLT转换 # 执行XSLT转换 要执行`XSLT`转换,请执行以下操作: - 如果使用的是`Xalan`处理器(对于`XSLT 1.0`),请使用`%XML.XSLT.Transformer`的以下类方法之一: - `TransformFile()`——转换给定XSLT样式表的文件。 - `TransformFileWithCompiledXSL()`——转换一个文件,给定一个已编译的XSLT样式表。 - `TransformStream()`——转换给定XSLT样式表的流。 - `TransformStreamWithCompiledXSL()`——转换一个流,给定一个已编译的XSLT样式表。 - `TransformStringWithCompiledXSL()`——转换给定已编译XSLT样式表的字符串。 - 如果使用`Saxon`处理器(用于XSLT 2.0),请使用`%XML.XSLT2.Transformer`的以下类方法之一: - `TransformFile()`——转换给定XSLT样式表的文件。 - `TransformFileWithCompiledXSL()`——转换一个文件,给定一个已编译的XSLT样式表。 - `TransformStream()`——转换给定XSLT样式表的流。 - `TransformStreamWithCompiledXSL()`——转换一个流,给定一个已编译的XSLT样式表。 这些方法具有相似的签名。这些方法的参数列表按顺序如下: - pSource—要转换的源XML。请参见此列表后面的表。 - pXSL -样式表或编译样式表。请参阅此列表后面的表格。 - pOutput -作为输出参数返回的结果XML。请参阅此列表后面的表格。 - pErrorHandler -一个可选的自定义错误处理程序。请参阅本章后面的“自定义错误处理”。如果不指定自定义错误处理程序,该方法将使用%XML.XSLT.ErrorHandler的新实例(对于两个类)。 - pParms -一个可选的InterSystems IRIS多维数组,包含要传递给样式表的参数。 - pCallbackHandler -定义`XSLT`扩展函数的可选回调处理程序。 - pResolver -一个可选的实体解析器。 8. (仅适用于`%XML.XSLT2.Transformer`)网关-`%Net.Remote.Gateway`的可选实例。如果要重用XSLT网关连接以获得更好的性能,请指定此参数; 作为参考,下表显示了这些方法的前三个参数,并进行了对比: XSLT变换方法的比较 Method | pSource (Input XML) |pXSL (Stylesheet) |pOutput(Output XML) ---|---|---|--- TransformFile() |String that gives a file name| String that gives a file name |String that gives a file name TransformFileWithCompiledXSL()| String that gives a file name |Compiled style sheet| String that gives a file name TransformStream()| Stream| Stream |Stream, returned by reference TransformStreamWithCompiledXSL()| Stream |Compiled style sheet |Stream, returned by reference TransformStringWithCompiledXSL()| String |Compiled style sheet| String that gives a file name # 示例 本节使用以下代码(但不同的输入文件)展示了几种转换: ```java Set in="c:\0test\xslt-example-input.xml" Set xsl="c:\0test\xslt-example-stylesheet.xsl" Set out="c:\0test\xslt-example-output.xml" Set tSC=##class(%XML.XSLT.Transformer).TransformFile(in,xsl,.out) Write tSC ``` ## 示例1:简单替换 在本例中,我们从以下输入XML开始: ```xml Content ``` 我们使用以下样式表: ```xml Content Replaced ``` 在这种情况下,输出文件将如下所示: ```xml Content Replaced ``` ## 示例2:内容提取 在本例中,我们从以下输入XML开始: ```xml Some text Some more text ``` 我们使用以下样式表: ```xml : ``` 在这种情况下,输出文件将如下所示: ```java 13: Some text 14: Some more text ``` ## 其他示例 InterSystems IRIS提供了以下附加示例: - 对于`XSLT 1.0`,请参阅`%XML.XSLT.Transformer`中的`Example()`、`Example2()`和其它方法。 - 对于`XSLT 2.0`,请参见`Samples`命名空间中的类`XSLT2.Examples`。
文章
姚 鑫 · 六月 30, 2021

第二十三章 执行XSLT转换

# 第二十三章 执行XSLT转换概述 XSLT(Extensible StyleSheet Language Transformations,可扩展样式表语言转换)是一种基于XML的语言,用于描述如何将给定的XML文档转换为另一个XML或其他“人类可读”的文档。可以使用`%XML.XSLT`和`%XML.XSLT2`包中的类来执行`XSLT 1.0`和`2.0`转换。 注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码, IRIS将使用本书前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。 # 在IRIS中执行XSLT转换概述 IRIS提供两个XSLT处理器,每个处理器都有自己的API: - `Xalan`处理器支持`XSLT 1.0`。`XML.XSLT`包为该处理器提供API。 - `Saxon`处理器支持`XSLT 2.0`。`%XML.XSLT2`程序包为该处理器提供API。 `XML.XSLT2` API通过到`XSLT 2.0`网关的连接向`Saxon`发送请求。网关允许多个连接。这意味着,例如,可以将两个独立的 IRIS进程连接到网关,每个进程都有自己的一组编译样式表,同时发送转换请求。 使用Saxon处理器,编译的样式表和`isc:Evaluate`缓存是特定于连接的;必须管理自己的连接才能利用这两个特性。如果打开连接并创建编译样式表或计算填充`isc:Evaluate`缓存的转换,则在该连接上计算的所有其他转换都将访问编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。 这两个处理器的API相似,不同之处在于`%XML.XSLT2`中的方法使用另一个参数来指定要使用的网关连接。 要执行`XSLT`转换,请执行以下操作: 1. 如果使用的是`Saxon`处理器,请按照下一节所述配置`XSLT`网关服务器。或使用默认配置。 如果使用的是`Xalan`处理器,则不需要网关。 系统会在需要时自动启动网关。或者也可以手动启动它。 2. 如果使用的是`Saxon`处理器,则可以选择创建`%Net.Remote.Gateway`的实例,表示到`XSLT`网关的单个连接。 请注意,当使用`Saxon`处理器时,要利用已编译的样式表和`isc:Evaluate`缓存,这一步是必需的。 3. 可以选择创建已编译的样式表并将其加载到内存中。请参阅本章后面的“创建编译样式表”。如果使用的是`Saxon`处理器,请确保在创建编译后的样式表时指定网关参数。 如果打算重复使用同一样式表,则此步骤非常有用。然而,此步骤也会消耗内存。当不再需要编译的样式表时,请务必将其删除。 4. 调用适用API的转换方法之一。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数。 5. 可以选择调用其他转换方法。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数;这使能够使用相同的连接计算另一个转换。此转换将访问与此连接相关联的所有编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。 Studio还提供了一个向导,可以使用该向导测试XSLT转换;本章稍后将对此进行介绍。 # 配置、启动和停止XSLT 2.0网关 当使用`Saxon`处理器(执行`XSLT 2.0`转换)时, IRIS使用`XSLT 2.0`网关(后者使用Java)。要配置此网关,请执行以下操作: 1. 在管理门户中,选择 System Administration > Configuration > Connectivity > XSLT 2.0 Gateway Server. 2. 选择Go。 ![image](/sites/default/files/inline/images/1_49.png) 系统将显示XSLT网关服务器页面。 左侧区域显示配置详细信息,右侧区域显示最近的活动。 ![image](/sites/default/files/inline/images/2_29.png) 3. 在左侧区域中,可以选择指定以下设置: - Port Number -`XSLT 2.0`网关独占使用的TCP端口号。此端口号不得与服务器上的任何其他本地TCP端口冲突。 默认值为 IRIS SuperServer端口号加`3000`。如果此数字大于`65535`,则系统使用`54773`。 - Java Version - 使用的Java版本。 - Log File - 日志文件的路径名。如果忽略此设置,则不执行日志记录。如果指定了文件名但忽略了目录,则将日志文件写入系统管理器的目录。 - Java Home Directory -包含Java bin目录的目录路径。如果服务器上没有默认Java,或者如果想使用不同的Java,请指定此选项。 要查看默认Java,请在服务器上的Shell中执行以下命令: ``` java -version ``` - JVM Arguments - Java虚拟机要使用的任何其他参数。 此区域还显示`JAVA_HOME`环境变量的当前值。 请注意,在网关运行时,不能编辑这些值中的任何一个。 4. 如果已进行更改,请选择保存以保存更改。或选择重置以。 5. (可选)选择测试以测试更改。 在此页面上,还可以执行以下操作: - 启动网关。要执行此操作,请选择右侧区域中的Start。 请注意, IRIS会在需要时自动启动网关。不需要手动启动网关。 - 关闭网关。要执行此操作,请选择右侧区域中的Stop(停止)。 # 重用XSLT网关服务器连接(XSLT 2.0) 如果使用的是`Saxon`处理器,InterSystems IRIS将使用之前配置的`XSLT 2.0`网关。为了与此网关通信,InterSystems IRIS在内部创建一个`XSLT`网关连接(`%Net.Remote.Gateway`的实例)。默认情况下,系统创建一个连接,将其用于转换,然后丢弃该连接。打开新连接会产生开销,因此为多个转换维护一个连接可提供最佳性能。此外,必须维护自己的连接,以便利用已编译的样式表和`isc:Evaluate`缓存。 要重用XSLT网关连接,请执行以下操作: 1. 调用`%XML.XSLT2.Transformer`的`StartGateway()`方法: ``` set status=##class(%XML.XSLT2.Transformer).StartGateway(.gateway) ``` 此方法启动XSLT 2.0网关(如果它尚未运行),并返回`%Net.Remote.Gateway`的实例作为输出。请注意,该方法还返回状态。 在`%Net.Remote.Gateway`实例表示与网关的连接。 `StartGateway()`有一个可选的第二个参数`useSharedMemory`。如果此参数为真(缺省值),则与`localhost`或`127.0.0.1`的连接将使用共享内存(如果可能)。要强制连接仅使用`TCP/IP`,请将此参数设置为False。 2. 检查上一步返回的状态: ```java if $$$ISERR(status) { quit } ``` 3. 创建任何已编译的样式表。执行此操作时,请将网关参数指定为`%Net.Remote.GatewayInstance`的实例在步骤1中创建。 4. 根据需要调用`%XML.XSLT2.Transformer`的`Transform`方法(`TransformFile()`、`TransformFileWithCompiledXSL()`、`TransformStream()`和`TransformStreamWithCompiledXSL()`)。执行此操作时,请将网关参数指定为在步骤1中创建的`%Net.Remote.Gateway`的实例。 5. 如果不再需要给定的编译样式表,请在调用`%XML.XSLT2.CompiledStyleSheet`的`ReleaseFromServer()`方法: ```java Set status=##class(%XML.XSLT2.CompiledStyleSheet).ReleaseFromServer(compiledStyleSheet,,gateway) ``` 重要提示:当不再需要已编译的样式表时,请务必使用此方法。 6. 当不再需要XSLT网关连接时,调用`%XML.XSLT2.Transformer`的`StopGateway()`方法,并将网关连接作为参数传递: ```java set status=##class(%XML.XSLT2.Transformer).StopGateway(gateway) ``` 此方法丢弃连接并重置当前设备。它不会停止`XSLT 2.0`网关。 重要提示:当不再需要连接时,请务必使用此方法。 有关示例,请参见XSLT2中的`Example10()`方法。`Samples`命名空间中的`Examples`。 # 排除XSLT 2.0网关服务器连接故障 当XSLT 2.0网关打开时,InterSystems IRIS和网关服务器之间的连接可能会变得无效。例如,如果出现网络错误或在InterSystems IRIS连接到网关服务器后重新启动网关服务器,则连接可能无法正常关闭。因此,可能会遇到错误。 可以通过连续调用XSLT网关连接对象的`%LostConnectionCleanup()`方法和`%reconnect`方法,尝试将InterSystems IRIS重新连接到网关服务器。 如果希望在断开连接时自动重新连接到网关服务器,请将网关连接对象的`AttemptReconnect`属性设置为true。 # 创建编译的样式表 如果打算重复使用同一样式表,则可能需要编译该样式表以提高速度。请注意,此步骤会消耗内存。当不再需要编译的样式表时,请务必将其删除。 要创建编译的样式表,请执行以下操作: - 如果使用的是`Xalan`处理器(对于`XSLT 1.0`),请使用`%XML.XSLT.CompiledStyleSheet`的以下类方法之一: - `CreateFromFile()` - `CreateFromStream()` - 如果使用的是`Saxon`处理器(用于`XSLT 2.0`),请在使用`%XML.XSLT2.CompiledStyleSheet`的以下类方法之一: - `CreateFromFile()` - `CreateFromStream()` 另请注意,将需要创建一个XSLT网关连接;请参阅“重用XSLT网关服务器连接(`XSLT 2.0`)”。 对于所有这些方法,完整的参数列表按顺序如下: 1. source - 样式表。 对于`CreateFromFile()`,此参数是文件名。对于`CreateFromStream()`,此参数是一个流。 2. compiledStyleSheet - 编译后的样式表,作为输出参数返回。 这是样式表类(`%XML.XSLT.CompiledStyleSheet`或`%XL.XSLT2.CompiledStyleSheet`,视情况而定)的实例。 3. errorHandler - 编译样式表时使用的可选自定义错误处理程序。 对于这两个类中的方法,这是`%XML.XSLT.ErrorHandler`实例。 4. (仅适用于`%XML.XSLT2.CompiledStyleSheet`)网关-`%Net.Remote.Gateway`的实例 ``` //将tXSL设置为等于适当流的OREF Set tSC=##class(%XML.XSLT.CompiledStyleSheet).CreateFromStream(tXSL,.tCompiledStyleSheet) If $$$ISERR(tSC) Quit ```
文章
jieliang liu · 六月 30, 2021

如何在InterSystems开发者社区学习?第一部分:玩转“关注”

嗨,开发者们! 在这篇文章中,我们想告诉你如何充分利用开发者社区,从InterSystems的技术专家那里学到尽可能多的东西! 请注意这些步骤,以成为我们社区的高级用户! 关注你感兴趣的社区成员 如果你喜欢他们发布的内容,你可以关注社区的任何成员。只需点击任何成员右侧边栏上的 "关注 "按钮,当该成员在社区上发表文章(文章/问题/公告等)时,你将收到电子邮件通知。 此外,在主页的顶部菜单中,你可以点击 "成员",搜索特定的人或有更多意见的成员,或更多的喜欢......并开始关注他们。 关注你感兴趣的标签 用于描述社区上的帖子的所有标签都可以在DC主页上的 "标签 "部分找到: 在DC标签树中, 您可以找到您感兴趣的主题并关注相关的 标签。只需选择一个标签并点击其旁边的 "关注 "按钮即可。当您关注任何标签时,您会收到一封包含所有使用该标签的帖子的电子邮件。 我们建议从以下标签开始: 最佳实践 | 技巧和窍门 | 初学者 | 教程 关注你所感兴趣的帖子 关注一个帖子,你将收到(通过电子邮件)该帖子的所有更新,如新的评论,或如果发表了第二部分,或任何其他与你关注的帖子有关的活动。 要关注一个帖子,你只需要点击每个帖子下面的铃铛图标。 -> 我如何知道我在关注哪些会员、标签和帖子? 要知道你所关注的会员、标签和帖子,你只需要进入你的账户,在右上角 然后进入左栏的 "订阅"。 在这个页面的底部,你可以在三个标签中看到并定制你的订阅--每个标签都显示你所关注的成员、标签和帖子。例如,下面的截图显示,用户正在关注一些标签和DC成员。 注意: 如果你想关注不同语言的会员或标签,你需要将你的订阅设置切换到你感兴趣的语言。 添加帖子到你的书 把你喜欢的帖子加入书签,这样你以后就可以快速而方便地访问该帖子。 如果你喜欢一个帖子(文章、问题或公告)并想把它保存起来,你可以把它添加到你的书签中。这样,你就可以快速和容易地访问该帖子,并在你想要时阅读它。 要将一个帖子添加到你的书签,你只需要点击每个帖子下面的星星图标。 要查看您的所有书签,请进入您的账户,然后在左栏中进入 "书签"。 所以,开发者们! 请使用我们所有的DC功能,这些功能可以帮助你成为InterSystems技术的专家! 而且非常欢迎你在下面的评论中提交关于如何在开发者社区学习InterSystems技术的其他方法和建议。
文章
姚 鑫 · 六月 29, 2021

第二十二章 计算XPath表达式

# 第二十二章 计算XPath表达式 `XPath`(XML路径语言)是一种基于XML的表达式语言,用于从XML文档获取数据。使用类中的`%XML.XPATH.Document`,可以轻松地计算`XPath`表达式(给定提供的任意XML文档)。 注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用本书前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。 ## IRIS中XPath表达式求值概述 要使用InterSystems IRIS XML支持使用任意XML文档计算`XPath`表达式,请执行以下操作: 1. 创建`%XML.XPATH.Document`的实例。为此,请使用以下类方法之一:`CreateFromFile()`、`CreateFromStream()`或`CreateFromString()``。使用这些方法中的任何一种,都可以将输入XML文档指定为第一个参数,并接收%XML.XPATH.Document`的一个实例作为输出参数。 这一步使用内置的XSLT处理器解析XML文档。 2. 使用`%XML.XPATH.Document`实例的`EvaluateExpression()`方法。对于此方法,需要指定节点上下文和要计算的表达式。 节点上下文指定要在其中计算表达式的上下文。这使用`XPath`语法来表示到所需节点的路径。例如: ```java "/staff/doc" ``` 要计算的表达式还使用`XPath`语法。例如: ```java "name[@last='Marston']" ``` 可以将结果作为输出参数(作为第三个参数)接收。 注意:如果要迭代一大组文档并计算每个文档的`XPath`表达式,建议在处理完文档后,在打开下一个文档之前将该文档的`OREF`设置为`NULL`。这绕过了第三方软件的一个限制。在循环中处理大量文档时,此限制会导致CPU使用率略有增加。 # 创建XPath文档时的参数列表 若要在创建`%XML.XPATH.Document`的实例,请使用该类的`CreateFromFile()`、`CreateFromStream()`或`CreateFromString()`类方法。对于这些类方法,完整的参数列表按顺序如下: 1. PSource、pStream或pString-源文档。 - 对于`CreateFromFile()`,此参数是文件名。 - 对于`CreateFromStream()`,此参数是二进制流。 - 对于`CreateFromString()`,此参数是一个字符串。 2. PDocument-作为输出参数返回的结果。这是`%XML.XPATH.Document`的实例。 3. PResolver-解析源时使用的可选实体解析器。 4. PErrorHandler-一个可选的自定义错误处理程序。 5. PFlags-控制SAX解析器执行的验证和处理的可选标志。 6. PSchemaSpec-可选的架构规范,用于验证文档源。此参数是一个字符串,其中包含以逗号分隔的命名空间/URL对列表: ```java "namespace URL,namespace URL" ``` 这里,`Namespace`是用于模式的XML名称空间,URL是提供模式文档位置的URL。名称空间和URL值之间有一个空格字符。 7. PPrefix Mappings-可选的前缀映射字符串。 `CreateFromFile()`、`CreateFromStream()`和`CreateFromString()`方法返回应检查的状态。例如: ```java Set tSC=##class(%XML.XPATH.Document).CreateFromFile("c:\sample.xml",.tDocument) If $$$ISERR(tSC) Do $System.OBJ.DisplayError(tSC) ``` # 为默认命名空间添加前缀映射 当XML文档使用默认名称空间时,这会给`XPath`带来问题。请考虑以下示例: ```xml Mr. Marston Mr. Bertoni Mr. Leslie Ms. Farmer ``` 在本例中, `` 元素属于名称空间,但没有名称空间前缀。`XPath`不提供访问 `` 元素的简单方法。 - 可以设置`%XML.XPATH.Document`实例的`Prefix Mappings`属性。该属性旨在为源文档中的每个默认名称空间提供唯一的前缀,以便`XPath`表达式可以使用这些前缀,而不是使用完整的名称空间URI。 `PrefixMappings` 属性是一个由逗号分隔的列表组成的字符串;每个列表项都是一个前缀,后跟一个空格,后跟一个命名空间URI。 - 调用`CreateFromFile()`、`CreateFromStream()`或`CreateFromString()`时,可以指定`PrefixMappings`参数。此字符串的格式必须与前面描述的相同。 然后以与使用任何名称空间前缀相同的方式使用这些前缀。 例如,假设将前面的XML读入`%XML.XPATH.Document`的实例时,按如下方式指定了前缀映射: ```java "s http://www.staff.org" ``` 在本例中,可以使用`"/s:staff/s:doc"`访问`` 元素。 请注意,可以使用实例方法`GetPrefix()`来获取先前为文档中的给定路径指定的前缀。 # 计算XPath表达式 要计算`XPath`表达式,请使用`%XML.XPATH.Document`实例的`EvaluateExpression()`方法。对于此方法,请按顺序指定以下参数: 1. PContext-节点上下文,指定在其中计算表达式的上下文。指定一个字符串,该字符串包含指向所需节点的路径的`XPath`语法。例如: ```java "/staff/doc" ``` 2. PExpression-选择特定结果的谓词。指定包含所需XPath语法的字符串。例如: ```java "name[@last='Marston']" ``` 注意:对于其他技术,通常的做法是将谓词连接到节点路径的末尾。类中的`%XML.XPATH.Document`不支持此语法,因为基础XSLT处理器需要节点上下文和谓词作为单独的参数。 3. PResults-作为输出参数返回的结果。 `EvaluateExpression()`方法返回应该检查的状态。例如: ```java Set tSC=tDoc.EvaluateExpression("/staff/doc","name[@last='Smith']",.tRes) If $$$ISERR(tSC) {Do $System.OBJ.DisplayError(tSC)} ``` # 使用XPath结果 XPath表达式可以返回XML文档的一个子树、多个子树或标量结果。在`%XML.XPATH.Document`的`EvaluateExpression()`方法旨在处理所有这些情况。具体地说,它返回一个结果列表。该列表中的每个项目都有一个Type属性,该属性具有下列值之一: - `$$$XPATHDOM`-指示该项包含XML文档的子树。此项目是`%XML.XPATH.DOMResult`实例,提供导航和检查子树的方法。 - `$$$XPATHVALUE`-指示该项是单个标量结果。此项目是`%XML.XPATH.ValueResult`实例。 这些宏在`%occXSLT.inc`包含文件中定义。 ## 检查XML子树 本节介绍如何导航由`%XML.XPATH.DOMResult`表示的XML子树,以及如何获取有关您在该子树中当前位置的信息。 ### 导航子树 要导航`%XML.XPATH.DOMResult`的实例,可以使用该实例的以下方法:`Read()`、`MoveToAttributeIndex()`、`MoveToAttributeName()`、`MoveToElement()`和`Rewind()`。 要移动到文档中的下一个节点,请使用`read()`方法。`Read()`方法返回TRUE值,直到没有更多节点可读为止(即,直到到达文档末尾)。 导航到某个元素时,如果该元素具有属性,则可以使用以下方法导航到这些属性: - 使用`MoveToAttributeIndex()`方法按索引(属性在元素中的序号位置)移动到特定属性。此方法只有一个参数:属性的索引号。请注意,可以使用`AttributeCount`属性来了解给定元素有多少个属性。 - 使用`MoveToAttributeName()`方法按名称移动到特定属性。此方法有两个参数:属性名称和命名空间URI(可选)。 完成当前元素的属性后,可以通过调用其中一个导航方法(如`read()`)移动到文档中的下一个元素。或者,可以调用`MoveToElement()`方法返回到包含当前属性的元素。 这里描述的所有方法都在文档中前进,但`Rewind()`方法除外,它导航到文档的开头并重置所有属性。 ### 节点的属性 除`Type`属性外,`%XML.XPATH.DOMResult`的以下属性还提供有关当前位置的信息。 #### AttributeCount 如果当前节点是元素,则此属性指示元素的属性数。 #### EOF 如果读取器已到达源文档的末尾,则为true;否则为false。 #### HasAttributes 如果当前节点是一个元素,则如果该元素具有属性,则此属性为true(如果没有属性,则为false)。如果当前节点是属性,则此属性为true。 对于任何其他类型的节点,此属性为False。 #### HasValue 如果当前节点是具有值的节点类型(即使该值为空),则为True。否则,此属性为false。 #### LocalName 对于属性或元素类型的节点,这是当前元素或属性的名称,不带命名空间前缀。对于所有其他类型的节点,此属性为`NULL`。 #### Name 当前节点的完全限定名称,视节点类型而定。 #### NodeType 当前节点的类型,如下之一:`attribute`, `chars`, `cdata`, `comment`, `document`, `documentfragment`, `documenttype`, `element`, `entity`, `entityreference`, `notation`,或处理指令。 #### Path 对于元素类型的节点,这是到元素的路径。 对于所有其他类型的节点,此属性为空。 #### ReadState 表示总体读状态,有以下几种: - `“initial”`表示`Read()`方法还没有被调用。 - `“cursoractive”`意味着`Read()`方法至少被调用过一次。 - `“eof”`表示已经到达文件的末尾。 #### Uri 当前节点的URI。 返回的值取决于节点的类型。 #### Value 值(如果有的话),适合于节点类型。 如果该值小于`32kb`,则为字符串。 否则,它是一个字符流。 ## 检查标量结果 本节介绍在类中使用由`%XML.XPATH.ValueResult`表示的`XPath`结果。除`Type`属性外,该类还提供`Value`属性。 请注意,如果该值的长度大于32KB,则会自动将其放入流对象中。除非确定将收到的结果类型,否则应该检查`Value`是否为流对象。为此,可以使用`$IsObject`函数。(也就是说,如果此值是对象,则它是流对象,因为它是唯一可以是对象的类型。) ```java // 如果结果长度大于32KB,则值可以是流 Set tValue=tResult.Value If $IsObject(tValue){ Write ! Do tValue.OutputToDevice() } else { Write tValue } ``` ## 一般方法 除非可以确定在计算`XPath`表达式时会收到什么样的结果,否则应该编写代码来处理最常见的情况。代码的可能组织如下: 1. 查找返回结果列表中的元素数量。遍历此列表。 2. 对于每个列表项,检查`Type`属性。 - 如果`Type`为`$$$XPATHDOM`,, 在类中使用`%XML.XPATH.DOMResult`的方法导航并检查此XML子树。 - 如果`Type`为`$$$XPATHVALUE`,请检查`Value`属性是否为流对象。如果是流对象,则使用常用的流接口访问数据。否则,`Value`属性为字符串。 # 示例 本节中的示例针对以下`XML`文档计算`XPath`表达式: ```xml Yao Xin Mr. Bertoni Mr. Leslie Ms. Farmer Ms. Midy Mr. Dick Mr. Boag Mr. Curcuru Mr. Kesselman Mr. Auriemma ``` ## 计算具有子树结果的XPath表达式 ```java /// 计算返回DOM Result的XPath表达式 ClassMethod Example1() { Set tSC=$$$OK do { Set tSC=##class(%XML.XPATH.Document).CreateFromFile(filename,.tDoc) If $$$ISERR(tSC) {Do $System.OBJ.DisplayError(tSC) Quit} Set context="/staff/doc" Set expr="name[@last='Marston']" Set tSC=tDoc.EvaluateExpression(context,expr,.tRes) If $$$ISERR(tSC) Quit Do ##class(%XML.XPATH.Document).ExampleDisplayResults(tRes) } while (0) If $$$ISERR(tSC) {Do $System.OBJ.DisplayError(tSC)} Quit } ``` 本例选择了``元素的`last`属性等于`Yao`的任何节点。 该表达式在``元素的``节点中计算。 请注意,此示例使用`%XML.XPATH.Document`的`ExampleDisplayResults()`类方法。 执行`example1()`方法时,将先前的XML文件作为输入提供,您会看到以下输出: ```java DHC-APP>d ##class(PHA.TEST.Xml).Example1("E:\temp\xmlXpath.txt") XPATH DOM element: name attribute: first Value: Xin attribute: last Value: Yao chars : #text Value: Yao Xin ``` ## 计算具有标量结果的`XPath`表达式 下面的类方法读取XML文件并计算返回标量结果的XPath表达式: ```java /// 计算返回值结果的XPath表达式 /// d ##class(PHA.TEST.Xml).Example2("E:\temp\xmlXpath.txt") ClassMethod Example2(filename) { Set tSC=$$$OK do { Set tSC=##class(%XML.XPATH.Document).CreateFromFile(filename,.tDoc) If $$$ISERR(tSC) {Do $System.OBJ.DisplayError(tSC) Quit} Set tSC=tDoc.EvaluateExpression("/staff","count(doc)",.tRes) If $$$ISERR(tSC) Quit Do ##class(%XML.XPATH.Document).ExampleDisplayResults(tRes) } while (0) If $$$ISERR(tSC) {Do $System.OBJ.DisplayError(tSC)} Quit } ``` 这个例子统计``子节点。 该表达式在``元素中求值。 当执行`Example2()`方法,提供前面的XML文件作为输入时,会看到以下输出: ```java DHC-APP> d ##class(PHA.TEST.Xml).Example2("E:\temp\xmlXpath.txt") XPATH VALUE 2 ```
文章
姚 鑫 · 六月 26, 2021

第十九章 使用%XML.TextReader

# 第十九章 使用%XML.TextReader `%XML.TextReader`类提供了一种简单、容易的方法来读取可能直接映射到InterSystems IRIS对象,也可能不直接映射到InterSystems IRIS对象的任意XML文档。具体地说,该类提供了导航格式良好的XML文档并查看其中信息(元素、属性、注释、名称空间URI等)的方法。该类还基于`DTD`或`XML`架构提供完整的文档验证。但是,与`%XML.Reader`不同的是,`%XML.TextReader`不提供返回`DOM`的方法。如果需要DOM,请参阅前面的“将XML导入对象”一章。 **注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。** # 创建文本阅读器`Text Reader`方法 要读取不一定与 IRIS对象类有任何关系的任意XML文档,可以调用`%XML.TextReader`类的方法,该类将打开文档并将其作为文本阅读器对象加载到临时存储中。文本阅读器对象包含一个可导航的节点树,每个节点都包含有关源文档的信息。然后,方法可以导航该文档并查找有关该文档的信息。对象的属性提供有关文档的信息,这些信息取决于在文档中的当前位置。如果存在验证错误,这些错误也可以作为树中的节点使用。 ## 整体结构 法应执行以下部分或全部操作: 1. 通过以下方法之一的第一个参数指定文档源: `Method`| `First Argument` ---|--- `ParseFile()` |文件名,带有完整路径。请注意,文件名和路径只能包含ASCII字符。 `ParseStream()`|流 `ParseString()`| 字符串 `ParseURL()`| URL **在任何情况下,源文档都必须是格式良好的XML文档;也就是说,它必须遵守XML语法的基本规则。这些方法中的每一个都返回一个状态(`$OK`或失败代码),以指示结果是否成功。可以使用常用机制测试状态;特别是可以使用`$System.Status.DisplayError(status)`查看错误消息的文本。** 对于这些方法中的每一个,如果该方法返回$OK,则它通过引用(其第二个参数)返回包含XML文档中的信息的文本阅读器对象。 其他参数允许控制实体解析、验证、找到哪些项等。这些内容将在本章后面的“解析方法的参数列表”中介绍。 2. 检查解析方法返回的状态,并在适当的情况下退出。 如果解析方法返回$OK,则有一个与源XML文档相对应的文本阅读器对象。可以导航此对象。 文档可能包含`“element”`、`“endelement”`、`“startprefixmapping”`等节点。 重要提示:在任何验证错误的情况下,文档包含“错误”或“警告”节点。 代码应该检查这些节点。 3. 使用以下实例方法之一开始读取文档。 - 使用`Read()`导航到文档的第一个节点。 - 使用`ReadStartElement()`导航到特定类型的第一个元素。 - 使用`MoveToContent()`导航到类型为`“chars”`的第一个节点。 4. 获取该节点感兴趣的属性的值(如果有的话)。可用的属性包括名称、值、深度等。 5. 根据需要继续在文档中导航并获取属性值。 如果当前节点是元素,则可以使用`MoveToAttributeIndex()`或`MoveToAttributeName()`方法将焦点移至该元素的属性。若要返回到元素(如果适用),请使用`MoveToElement()`。 6. 如果需要,可以使用`Rewind()`方法返回到文档的开头(第一个节点之前)。这是唯一可以在源代码中倒退的方法。 方法运行后,文本读取器对象将被销毁,所有相关的临时存储都将被清除。 ## 示例1 下面是一个简单的方法,它可以读取任何XML文件,并显示每个节点的序列号、类型、名称和值: ```java /// w ##class(PHA.TEST.Xml).WriteNodes("E:\temp\textReader.txt") ClassMethod WriteNodes(myfile As %String) { set status = ##class(%XML.TextReader).ParseFile(myfile,.textreader) //检查状态 if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} //逐个节点遍历文档 while textreader.Read() { Write !, "Node ", textreader.seq, " is a(n) " Write textreader.NodeType," " If textreader.Name'="" { Write "named: ", textreader.Name } Else { Write "and has no name" } Write !, " path: ",textreader.Path If textreader.Value'="" { Write !, " value: ", textreader.Value } } q "" } ``` 此示例执行以下操作: 1. 它调用`ParseFile()`类方法。这将读取源文件,创建一个文本阅读器对象,并通过引用在变量doc中返回该对象。 2. 如果`ParseFile()`成功,则该方法然后调用`read()`方法来查找文档中的每个后续节点。 3. 对于每个节点,该方法写入包含节点序列号、节点类型、节点名称(如果有)、节点路径和节点值(如果有)的输出行。输出将写入当前设备。 以下示例源文档: ```xml yaoxin 1990-04-25 ``` 对于此源文档,前面的方法生成以下输出: ```java DHC-APP>w ##class(PHA.TEST.Xml).WriteNodes("E:\temp\textReader.txt") Node 1 is a(n) processinginstruction named: xml-stylesheet path: value: type="text/css" href="mystyles.css" Node 2 is a(n) element named: Root path: /Root Node 3 is a(n) startprefixmapping named: s01 path: /Root value: s01 http://www.root.org Node 4 is a(n) element named: s01:Person path: /Root/s01:Person Node 5 is a(n) element named: Name path: /Root/s01:Person/Name Node 6 is a(n) chars and has no name path: /Root/s01:Person/Name value: yaoxin Node 7 is a(n) endelement named: Name path: /Root/s01:Person/Name Node 8 is a(n) element named: DOB path: /Root/s01:Person/DOB Node 9 is a(n) chars and has no name path: /Root/s01:Person/DOB value: 1990-04-25 Node 10 is a(n) endelement named: DOB path: /Root/s01:Person/DOB Node 11 is a(n) endelement named: s01:Person path: /Root/s01:Person Node 12 is a(n) endprefixmapping named: s01 path: /Root value: s01 Node 13 is a(n) endelement named: Root path: /Root ``` 请注意,注释已被忽略;默认情况下,`%XML.TextReader`忽略注释。 ## Example 2 下面的示例读取一个XML文件并列出其中的每个元素 ```java /// w ##class(PHA.TEST.Xml).ShowElements("E:\temp\textReader.txt") ClassMethod ShowElements(myfile As %String) { set status = ##class(%XML.TextReader).ParseFile(myfile,.textreader) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} while textreader.Read() { if (textreader.NodeType = "element") { write textreader.Name,! } } q "" } ``` 此方法使用`NodeType`属性检查每个节点的类型。如果节点是元素,则该方法将其名称打印到当前设备。对于前面显示的XML源文档,此方法生成以下输出: ```java DHC-APP>w ##class(PHA.TEST.Xml).ShowElements("E:\temp\textReader.txt") Root s01:Person Name DOB ``` # 节点类型 文档的每个节点都是以下类型之一: 文本阅读器文档中的节点类型 Type| Description ---|--- `"attribute"` |XML属性。 `"chars"` |一组字符(如元素的内容)。`%XML.TextReader`类识别其他节点类型(`“CDATA”`、`“EntityReference”`和`“EndEntity”`),但自动将它们转换为“字符”。 `"comment"`| XML注释。 `"element"`|XML元素的开始。 `"endelement"`|XML元素的结束。 `"endprefixmapping"`| 声明名称空间的上下文的结束。 `"entity"`|XML实体。 `"error"`| 解析器发现的验证错误。 `"ignorablewhitespace"`| 混合内容模型中标记之间的空白。 `"processinginstruction"`|XML处理指令。 `"startprefixmapping"`|XML命名空间声明,它可能包括也可能不包括命名空间。 `"warning"`| 解析器发现验证警告。 请注意,XML元素由多个节点组成。例如,以下XML片段: ```xml Willeke,Clint B. 1925-10-01 ``` SAX解析器将此XML视为以下节点集: 文档节点示例 Node Number |Type of Node| Name of Node, If Any| Value of Node, If Any ---|---|---|--- 1 |element |Person 2| element |Name 3| chars || Willeke,Clint B. 4 |endelement| Name 5| element| DOB 6| chars || 1925-10-01 7| endelement| DOB 8| endelement| Person 例如,注意``元素被认为是三个节点:一个元素节点、一个字符节点和一个结束元素节点。还要注意,该元素的内容只能作为`chars`节点的值使用。
文章
姚 鑫 · 六月 25, 2021

第十八章 签署XML文档

# 第十八章 签署XML文档 本章介绍如何向XML文档添加数字签名。 # 关于数字签名文档 数字签名的XML文档包括一个或多个``元素,每个元素都是数字签名。 每个``元素对文档中的特定元素进行如下签名: - 每个签名元素都有一个ID属性,该属性等于某个唯一值。例如: ```xml ``` - 一个``元素包含一个``元素,它指向该Id,如下所示: ```xml ``` ``元素是由私钥签名的。此元素包括由签名机构签署的X.509证书。如果已签名文档的接收方信任此签名机构,则接收方可以验证证书,并使用包含的公钥验证签名。 注意: IRIS还支持一种变体,其中有签名的元素有一个名为ID的属性,而不是ID。 下面是一个示例,为了便于阅读,添加了空格: ```xml Persephone MacMillan 1976-02-20 FHwW2U58bztLI4cIE/mp+nsBNZg= MTha3zLoj8Tg content omitted MIICnDCCAYQCAWUwDQYJ content omitted ``` 要创建数字签名,可以使用类`%XML.Security.Signature`。 这是一个支持xml的类,它的投影是适当名称空间中的有效``元素。 # 创建数字签名XML文档 要创建数字签名的XML文档,请使用`%XML.Writer`为一个或多个适当定义的启用了XML的对象生成输出。 在为对象生成输出之前,必须创建所需的签名并将其写入对象,以便可以将信息写入目标。 ## 签名的前提条件 在签署文档之前,必须至少创建一个IRIS凭据集。InterSystems IRIS凭据集是存储在系统管理器数据库中的以下信息集的别名: - 包含公钥的证书。证书应由文档接收者信任的签名机构签名。 - 关联的私钥, IRIS在需要时使用,但从不发送。签名需要私钥。 - (可选)私钥的密码, IRIS在需要时使用私钥,但从不发送。可以加载私钥,也可以在运行时提供私钥。 ## 启用XML的类的要求 启用XML的类必须包括以下内容: - 投影为ID属性的特性。 - 至少一个类型为`%XML.Security`的属性。投影为``元素的签名。(一个XML文档可以包含多个``元素。) 考虑以下类: ```java Class XMLEncryption.Simple Extends (%RegisteredObject, %XML.Adaptor) { Parameter NAMESPACE = "http://mynamespace"; Parameter XMLNAME = "Person"; Property Name As %String; Property DOB As %String; Property PersonId As %String(XMLNAME = "Id", XMLPROJECTION = "ATTRIBUTE"); Property MySig As %XML.Security.Signature(XMLNAME = "Signature"); } ``` ## 生成和添加签名 要生成和添加数字签名,请执行以下步骤: 1. 可以选择包含`%soap.inc`包含文件,该文件定义可能需要使用的宏。 2. 创建`%SYS.X509Credentials`的实例在访问相应InterSystems IRIS凭据集。为此,调用`%SYS.X509Credentials`的`GetByAlias()`类方法。 ```java classmethod GetByAlias(alias As %String, pwd As %String) as %SYS.X509Credentials ``` - alias 别名是证书的别名。 - pwd 是私钥密码。仅当关联的私钥已加密并且在加载私钥文件时未加载密码时,才需要私钥密码。 若要运行此方法,必须以该凭据集的`OwnerList`中包含的用户身份登录,否则`OwnerList`必须为空。 3. 在使用给定凭据集创建 `%XML.Security.Signature`的实例。为此,请调用该类的`Createx509()`类方法: ```java classmethod CreateX509(credentials As %SYS.X509Credentials, signatureOption As %Integer, referenceOption As %Integer) as %XML.Security.Signature ``` - `credentials` 凭据是刚刚创建`%SYS.X509Credentials`的实例。 - `signatureOption`是`$$$SOAPWSIncludeNone`(还有其他选项,但它们不适用于此方案) - `referenceOption` 指定对符号元素的引用的性质。 这里使用的宏在`%soap.inc`中定义包括文件。 4. 获取ID属性的值,对于此签名将点的ID。此详细信息取决于启用XML对象的定义。 5. 创建`%XML.Security.Reference`的实例,指向该ID。为此,请调用该类的`Create()`类方法: ```java ClassMethod Create(id As %String, algorithm As %String, prefixList As %String) ``` - `id`是该参考应该指向的ID。 - `algorithm` 算法应该是以下之一: - `$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSexcc14`n — 使用此版本获取独占规范化。 - `$$$SOAPWSEnvelopedSignature` — 这相当于前面的选项。 - `$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSexcc14n` — 使用此版本进行包容性规范化。 6. 对于签名对象,调用`AddReference()`方法将此引用添加到签名: ```java Method AddReference(reference As %XML.Security.Reference) ``` 7. 更新启用XML的类的相应属性以包含签名。 ```java set object.MySig=signature ``` 8. 创建`%XML.Document`的实例,该实例包含序列化为XML的启用了XML的对象。 这是必要的,因为签名必须包括有关签名文档的信息。 注意:本文档不包含空格。 9. 调用签名对象的`SignDocument()`方法: ```java Method SignDocument(document As %XML.Document) As %Status ``` 此方法的参数是刚刚创建的中`%XML.Document`的实例。`SignDocument()`方法使用该实例中的信息更新签名对象。 10. 使用`%XML.Writer`中为对象生成输出。 注意:生成的输出必须包含与签名中使用的文档相同的空格(或不包含空格)。签名包含文档的摘要,如果将编写器中的缩进属性设置为1,则摘要将与文档不匹配。 例如: **放入到对应的实体类中,有一些属性需要替换** ```java Method WriteSigned(filename As %String = "") { #Include %soap //创建签名对象 set cred=##class(%SYS.X509Credentials).GetByAlias("servercred") set parts=$$$SOAPWSIncludeNone set ref=$$$KeyInfoX509Certificate set signature=##class(%XML.Security.Signature).CreateX509(cred,parts,ref,.status) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} // 获取我们要签名的元素的ID属性; set refid=$this.PersonId ; 此详细信息取决于类的结构 // 然后在签名对象中创建对该ID的引用 set algorithm=$$$SOAPWSEnvelopedSignature_","_$$$SOAPWSc14n set reference=##class(%XML.Security.Reference).Create(refid,algorithm) do signature.AddReference(reference) //设置MySig属性,以便$this具有我们为其生成输出时所需的所有信息 set $this.MySig=signature ; 此详细信息取决于类的结构 //除了$this之外,我们还需要%XML.Document的一个实例,该实例包含序列化为XML的对象 set document=..GetXMLDoc($this) //使用序列化的XML对象对文档进行签名,这将更新部分签名 set status=signature.SignDocument(document) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} // 写入对象的输出 set writer=##class(%XML.Writer).%New() if (filename'="") { set status=writer.OutputToFile(filename) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} } do writer.RootObject($this) } ``` 前面的实例方法使用以下泛型类方法,该方法可以与任何启用了XML的对象一起使用: ```java ClassMethod GetXMLDoc2(object) As %XML.Document { //步骤1-将对象作为XML写入流 set writer=##class(%XML.Writer).%New() set stream=##class(%GlobalCharacterStream).%New() set status=writer.OutputToStream(stream) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} set status=writer.RootObject(object) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} //步骤2-从流中提取%XML.Document set status=##class(%XML.Document).GetDocumentFromStream(stream,.document) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} quit document } ``` 变体:引用中带有`URI=""`的数字签名 作为一种变体,签名的``元素可以具有`URI=""`,这是对包含签名的XML文档根节点的引用。 要通过以下方式创建数字签名: 1. 可以选择包含`%soap.inc`包含文件,该文件定义可能需要使用的宏。 2. 创建`%SYS.X509Credentials`的实例在访问相应InterSystems IRIS凭据集。为此,请调用`%SYS.X509Credentials`的`GetByAlias()`类方法,如前面的步骤所述。 3. 创建使用给定凭据集的`%XML.Security.Signature`的实例。为此,请调用该类的`CreateX509()`类方法,如前面的步骤所述。 4. 按如下方式创建`%XML.Security.X509Data`的实例: ```java set valuetype=$$$KeyInfoX509SubjectName_","_$$$KeyInfoX509Certificate set x509data=##class(%XML.Security.X509Data).Create(valuetype,cred) ``` 其中,`cred`是`%SYS`的实例。 `x509credentials`在之前创建的新窗口中打开。 这些步骤创建了一个``元素,其中包含一个``元素和一个``元素。 5. 将``元素添加到签名的``元素中,方法如下: ```java do signature.KeyInfo.KeyInfoClauseList.Insert(x509data) ``` 其中签名是`%XML.Security`的实例。 `x509data`是`%XML.Security.X509Data`的实例。 6. 创建`%XML.Security`的实例。 参考如下: ```java set algorithm=$$$SOAPWSEnvelopedSignature set reference=##class(%XML.Security.Reference).Create("",algorithm) ``` 7. 在步骤6(调用`AddReference()`)中继续上述步骤。 # 验证数字签名 对于收到的任何数字签名文档,都可以验证签名。不需要具有与文档内容匹配的启用XML的类。 ## 验证签名的前提条件 若要验证数字签名,必须首先为签名者向InterSystems IRIS提供受信任的证书。如果InterSystems IRIS可以验证签名者的证书链(从签名者自己的证书到来自InterSystems IRIS信任的证书颁发机构(CA)的自签名证书),包括中间证书(如果有),则InterSystems IRIS可以验证签名。 ## 验证签名 要验证数字签名的XML文档中的签名,请执行以下操作: 1. 创建`%XML.Reader`的实例并使用它打开文档。 2. 获取阅读器的`Document`属性。这是 `%XML.Document`的一个实例。包含作为`DOM的XML文档的文档 3. 使用阅读器的`correlation()`方法将``元素或元素与类`%XML.Security.Signature`关联起来。 例如: ```java do reader.Correlate("Signature","%XML.Security.Signature") ``` 4. 遍历文档以读取``元素或多个元素。为此,可以使用阅读器的`Next()`方法,该方法通过引用返回一个导入的对象(如果有的话)。 例如: ```java if 'reader.Next(.isig,.status) { write !,"Unable to import signature",! do $system.OBJ.DisplayError(status) quit } ``` 导入的对象是`%XML.Security.Signature`的实例 5. 调用导入签名的`ValidateDocument()`方法。该方法的参数必须是`%XML`的实例。先前检索到的文档。 ```java set status=isig.ValidateDocument(document) ``` 例如: ```java ClassMethod ValidateDoc(filename As %String) { set reader=##class(%XML.Reader).%New() set status=reader.OpenFile(filename) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } set document=reader.Document //获取 元素 //假设只有一个签名 do reader.Correlate("Signature","%XML.Security.Signature") if 'reader.Next(.isig,.status) { write !,"无法导入签名",! do $system.OBJ.DisplayError(status) quit } set status=isig.ValidateDocument(document) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } } ``` # 变体:引用ID的数字签名 在典型的情况下,``元素包含一个``元素,该元素指向文档中其他地方的唯一Id。 InterSystems IRIS还支持一种变体,其中``元素指向名为ID(而不是ID)的属性。 在这种变体中,需要额外的工作来签署文档和验证文档。 要对文档进行数字签名,请遵循“创建数字签名XML文档”中的步骤,并进行以下更改: - 对于支持xml的类,包含一个作为ID属性而不是ID属性投影的属性。 - 在生成和添加签名时,调用`%XML`的`AddIDs()`方法。文档实例。 在获得序列化的XML文档之后,在调用签名对象的`SignDocument()`方法之前,执行此操作。 例如: ```java //设置MySig属性,使$this在为其生成输出时拥有所需的所有信息 set $this.MySig=signature ; 这个细节取决于类的结构 //除了$this之外,我们还需要%XML的实例 包含序列化为XML的对象的文档 set document=..GetXMLDoc($this) //***** 当签名引用ID属性时添加步骤 ***** do document.AddIDs() //使用序列化的XML对象对文档进行签名,这更新了部分签名 set status=signature.SignDocument(document) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} ``` - 当验证文档时,在调用`Correlate()`之前包含以下步骤: 1. 调用 `%XML.Document`的`AddIDs()`方法。 2. 调用XML阅读器的`Rewind()`方法。 例如: ``` set document=reader.Document //添加签名引用ID属性时的步骤 do document.AddIDs() do reader.Rewind() //获取 元素 do reader.Correlate("Signature","%XML.Security.Signature") ```
文章
姚 鑫 · 六月 24, 2021

第十七章 加密XML文档

# 第十七章 加密XML文档 本章介绍如何加密XML文档。 提示:发现在此命名空间中启用`SOAP`日志记录非常有用,这样就可以收到有关任何错误的更多信息。 # 关于加密的XML文档 加密的XML文档包括以下元素: - ``元素,其中包含由随机生成的对称密钥加密的加密数据。(使用对称密钥加密比使用公钥加密更有效。) - 至少有一个``元素。每个``元素携带用于加密数据的对称密钥的加密副本;它还包含一个带有公钥的`X.509`证书。拥有匹配私钥的接收方可以解密对称密钥,然后解密``元素。 - (可选)其他明文元素。 ```xml MIICnDCCAYQCAWUwDQYJKo... content omitted J2DjVgcB8vQx3UCy5uejMB ... content omitted LmoBK7+nDelTOsC3 ... content omitted ``` 要创建加密文档,请使用类`%XML.Security.EncryptedData`和`%XML.Security.EncryptedKey`。这些启用XML的类投影到适当名称空间中的有效``和``元素。 # 创建加密的XML文档 创建加密的XML文档的最简单方法如下: 1. 定义并使用可以直接投影到所需XML文档的通用容器类。 2. 创建包含要加密的XML的流。 3. 加密该流,并将其与相应的加密密钥一起写入容器类的相应属性。 4. 为容器类生成XML输出。 ## 加密的前提条件 在加密文档之前,必须创建包含要将加密文档发送到的实体的证书的 IRIS凭据集。在这种情况下,不需要(也不应该拥有)关联的私钥。 ## 容器类的要求 一个通用容器类必须包括以下内容: - 类型为`%XML.Security`的属性。 被投影为``元素的`EncryptedData`。 这个属性将携带加密的数据。 - 至少一个类型为`%XML.Security`的属性。被投影为``元素的`EncryptedKey`。 这些属性将携带相应的密钥信息。 示例如下: ```java Class XMLEncryption.Container Extends (%RegisteredObject, %XML.Adaptor) { Property Data As %XML.Security.EncryptedData(XMLNAME = "EncryptedData"); Property Key As %XML.Security.EncryptedKey(XMLNAME = "EncryptedKey"); Parameter NAMESPACE = "http://www.w3.org/2001/04/xmlenc#"; } ``` ## 生成加密的XML文档 要生成并编写加密文档,请执行以下操作: 1. 创建包含XML文档的流。 为此,通常使用`%XML.Writer`将启用XML的对象的输出写入流。 2. 创建`%SYS.X509Credentials`的至少一个实例,将访问要向其提供加密文档的实体的InterSystems IRIS凭据集。为此,请调用此类的`GetByAlias()`类方法。例如: ```java set credset=##class(%SYS.X509Credentials).GetByAlias("recipient") ``` 若要运行此方法,必须以该凭据集的`OwnerList`中包含的用户身份登录,否则`OwnerList`必须为空。 3. 至少创建`%XML.Security.EncryptedKey`实例。若要创建此类的实例,请使用此类的`CreateX509()`类方法。例如: ```java set enckey=##class(%XML.Security.EncryptedKey).Createx509(credset,encryptionOptions,referenceOption) ``` - `credset`是`%SYS`的实例。 `x509credentials`在刚刚创建的新窗口中打开。 - `encryptionOptions`是`$$$SOAPWSIncludeNone`(还有其他选项,但它们不适用于此场景)。 此宏在`%soap.inc`包含文件中定义。 - `referenceOption`指定了对加密元素的引用的性质。 这里使用的宏在`%soap.inc`包含文件中定义。 4. 在创建`%Library.ListOfObjects`实例,并使用其`Insert()`方法在刚创建插入`%XML.Security.EncryptedKey`实例。 5. 使用`%New()`方法创建`%XML.Security.EncryptedData`实例。例如: ```java set encdata=##class(%XML.Security.EncryptedData).%New() ``` 6. 使用`%XML.Security.EncryptedData的EncryptStream()`实例方法加密在步骤2中创建的流。例如: ```java set status=encdata.EncryptStream(stream,encryptedKeys) ``` - stream 流是在步骤1中创建的流。 - encryptedKeys是在步骤4中创建的密钥列表。 7. 创建并更新容器类的实例。 - 将键列表写入此类的相应属性。 - 将 `%XML.Security.EncryptedData`的实例写入此类的相应属性。 8. 使用`%XML.Writer`为容器类生成输出。 例如,前面显示的`CONTAINER`类还包括以下方法: ```java /// w ##class(XMLEncryption.Container).Demo("E:\temp\SecurityXml.txt") ClassMethod Demo(filename = "", obj = "") { #Include %soap if (obj = "") { s obj = ##class(MyApp.Person).%OpenId(1) } //从此启用XML的对象创建流 set writer = ##class(%XML.Writer).%New() set stream = ##class(%GlobalCharacterStream).%New() set status = writer.OutputToStream(stream) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } set status = writer.RootObject(obj) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } do stream.Rewind() set container = ..%New() ; 这就是我们要写出的对象 set cred = ##class(%SYS.X509Credentials).GetByAlias("servercred") set parts =$$$SOAPWSIncludeNone set ref = $$$KeyInfoX509Certificate set key = ##class(%XML.Security.EncryptedKey).CreateX509(cred, parts, ref) set container.Key = key ; 这个细节取决于类 //需要创建一个键列表(本例中仅为一个) set keys = ##class(%Collection.ListOfObj).%New() do keys.Insert(key) set encdata = ##class(%XML.Security.EncryptedData).%New() set status = encdata.EncryptStream(stream, keys) set container.Data = encdata ; 这个细节取决于类 // 为容器写输出 set writer = ##class(%XML.Writer).%New() set writer.Indent = 1 if (filename'="") { set status = writer.OutputToFile(filename) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} } set status = writer.RootObject(container) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} } ``` 此方法可以接受任何启用XML的类的`OREF`;如果没有提供,则使用默认值。 # 解密加密的XML文件 ## 解密的前提条件 在解密加密的`XML`文档之前,必须同时提供以下两项: - IRIS要使用的受信任证书。 - IRIS凭据集,其私钥与加密中使用的公钥匹配。 ## 解密文档 要解密加密的XML文档,请执行以下操作: 1. 创建`%XML.Reader`实例打开并使用它打开文档。 2. 获取`Document`属性,`%XML.Reader`实例。 其中包含作为DOM的XML文档。 3. 使用阅读器的`correlation()`方法将``元素或元素与类`%XML.Security.EncryptedKey`关联起来。 例如: ```java do reader.Correlate("EncryptedKey","%XML.Security.EncryptedKey") ``` 4. 遍历文档以读取``元素或多个元素。 为此,可以使用阅读器的`Next()`方法,该方法通过引用返回一个导入的对象(如果有的话)。 例如: ```java if 'reader.Next(.ikey,.status) { write !,"Unable to import key",! do $system.OBJ.DisplayError(status) quit } ``` 导入的对象`是%XML.Security.EncryptedKey`的实例。 5. 创建`%Library.ListOfObjects`的实例。 并使用它的`Insert()`方法插入`%XML.Security.EncryptedKey`的实例。 刚从文档中获得的。 6. 调用类`%XML.Security.EncryptedData`的`ValidateDocument()`方法 ```java set status=##class(%XML.Security.EncryptedData).ValidateDocument(.doc,keys) ``` 第一个参数(通过引用返回)是在第2步中检索到的DOM的修改版本。 第二个参数是上一步中的键列表。 7. 可以选择使用`%XML.Writer`为修改后的DOM生成输出。 例如,前面显示的`CONTAINER`类包含以下类方法: ```java ClassMethod DecryptDoc(filename As %String) { #Include %soap set reader = ##class(%XML.Reader).%New() set status = reader.OpenFile(filename) if $$$ISERR(status) {do $System.Status.DisplayError(status) quit } set doc = reader.Document //获取元素 do reader.Correlate("EncryptedKey","%XML.Security.EncryptedKey") if 'reader.Next(.ikey,.status) { write !,"无法导入密钥",! do $system.OBJ.DisplayError(status) quit } set keys = ##class(%Collection.ListOfObj).%New() do keys.Insert(ikey) // 以下步骤返回解密的文档 set status = ##class(%XML.Security.EncryptedData).ValidateDocument(.doc,keys) set writer = ##class(%XML.Writer).%New() set writer.Indent = 1 do writer.Document(doc) quit $$$OK } ```
文章
Michael Lei · 六月 23, 2021

使用 Ansible 自动化部署 Caché 应用程序 - 第 1

部分 Ansible 帮助我解决了快速部署 Caché 和应用程序组件以进行数据平台基准测试的问题。 您可以使用相同的工具和方法来建立您的测试实验室、培训系统、开发或其他环境。 如果在客户站点部署应用程序,可以将大量部署自动化,并确保系统、Caché 和应用程序的配置符合您的应用程序最佳做法标准。 ## 概述 作为一名技术架构师,我们的团队职责之一是在不同供应商的硬件和操作系统上对 InterSystems 数据平台进行基准测试。 通常,基础架构是预发布版,在必须归还或移交给其他人之前,我们的时间有限,因此,快速准确地设置基准测试,让我们有尽可能多的时间来做真正的基准测试工作,这一点至关重要。  多年来,我们通过 shell 脚本小程序来自动执行许多基准测试安装任务,并从速查表和检查清单中剪切和粘贴,但此类操作非常密集,而且容易出错,特别是有许多服务器并且在不同的操作系统之间切换时 - 在 SLES 11、Red Hat 6、Red Hat 7、AIX 等操作系统上安装或使用服务的差异可能很微小,让人厌烦。 在研究了几个可用于自动化配置和管理系统的软件选项之后,我选择了 Ansible 来执行预置数据平台、应用程序和基准测试组件的任务。 需要注意的是,我并没有规定 Ansible 是部署和配置的 **THE** 解决方案。 在选择 Ansible 之前,我研究了其他工具(如 Puppet 和 Chef)的功能和操作。 如果您的组织已经在使用其他工具,您可以使用它们 — 我在 Ansible 中使用的方法和命令等等应该可以转换到其他软件中,我希望这些帖子可以帮助您,不管您使用的是什么工具。 这是本系列的第一个帖子,将介绍在部署 InterSystems 数据平台应用程序时如何使用 Ansible。 本帖介绍如何通过安装 Caché 打下基础,下一帖将扩展解决方案以包括应用程序安装,包括使用 %installer 类。 本帖涵盖: * Ansible 的概述和安装 * Ansible 便于管理和扩展的布局。 * 同时在一个或多个服务器上安装 Caché。 ## 什么是 Ansible? 通过 Ansible 可以在配置一个或多个服务器的同时将复杂的任务自动化,并可以非常简单地添加新服务器。 任务会设计成幂等(您可以在同一台服务器上多次运行相同的脚本,得到的服务器配置将是相同的)。 我选择 Ansible 执行预置任务的一个关键原因是它对系统的要求最低(Python 2.7,Linux 服务器上自带 ),而且它是一个自包含解决方案 — Ansible 代码只安装在控制服务器上,并使用推送架构,通过 OpenSSH 在目标服务器上运行命令和脚本。 所预置的服务器上不需要任何代理。 作为对比,Chef 和 Puppet 采用拉取架构,软件在客户端服务器(Web、数据库等)上加载,并且客户端不断轮询主服务器以查找更新。 Ansible 的推送架构也适合按照您的计划需求逐步实施服务器。 Ansible 是开源的,由社区维护。 Ansible, Inc 从 2015 年开始为 Red Hat 所拥有。 Ansible, Inc 有一个高级的生命周期产品 (Ansible Tower),并提供收费的支持和培训,不过本帖中的所有内容均使用开源命令行版本。 还有一个活跃的社区 (Ansible Galaxy),您可以从中下载许多预制的解决方案来完成大量任务,如安装 Web 服务器、ftp、kerbros,不胜枚举。 例如,对于完整的基准测试部署项目,我包括了一个下载的 Apache 模块,并自定义成在 RHEL、SLES 或 Solaris(以及其他平台)上安装和配置 Apache 2.x。 Ansible 的下载和安装说明可以在 Ansible 网站和 Github 上找到。 如果您有问题或希望做出贡献,可以访问活跃社区。 https://www.ansible.com/get-startedhttp://docs.ansible.com ## 安装 Ansible 本帖中的示例已经在运行 Red Hat 7.0 和 7.2 的虚拟机上进行了测试 - 我也在我的安装了 Centos 7 的笔记本电脑上使用 virtual box 和 vagrant 对 Ansible 控制器服务器进行了初始测试。 Caché 不需要安装在控制器上,所以您的操作系统选择要多于 Caché 支持的平台列表。 为了简单起见,我使用了当前适用于 Red Hat 的 rpm 版本的 Ansible (Ansible 1.9.4),更高的版本可以从 GitHub 获取。 在示例中,我安装的是 cache-2015.2.2.805.0-lnxrhx64,但相同的常规过程也适用于 HealthShare 或 Ensemble 发行版。 您将在后面看到,我们使用特定文件名、目录路径等变量来参数化安装选项。 在第一个帖子中,我将任务削减为基本的 Caché 安装,因此大多数任务是独立于平台的。 当 Ansible playbook 启动时,首要任务之一是获取目标机器的清单 — 操作系统、接口卡、内存详细信息、CPU 数量、磁盘布局等,当运行命令以从目标上运行的实际命令(例如,Red Hat 上的 service start httpd 与 SLES 上的 /etc/init.d/apache2 restart)中提取 Ansible 脚本命令时,将使用目标操作系统的这些信息。 我假定您已读过说明,并且已按照您的平台说明在控制机上安装了 Ansible。 Ansible 必须使用 Linux 系统作为控制器,但目标系统可以是 Linux 或 Windows。 有关 Windows 目标的更多信息,请参见 Ansible 文档。 ### 控制器系统安装示例:在 RHEL/CentOS 7 64 位上安装 Ansible 在 Red Hat 或 CentOS 上,必须先安装 epel-release (Extra Packages for Enterprise Linux) RPM,其中包含 Ansible。 epel 项目面向主要 Linux 发行版设计,提供了许多有用的开源软件包(网络、系统管理、监视等)。 [root@localhost tmp]# wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm : : [root@localhost tmp]# rpm -ivh epel-release-7-5.noarch.rpm : : [root@localhost tmp]# yum --enablerepo=epel info ansible Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Installed Packages Name : ansible Arch : noarch Version : 1.9.4 Release : 1.el7 Size : 7.0 M Repo : installed From repo : epel Summary : SSH-based configuration management, deployment, and task execution system URL : http://ansible.com License : GPLv3+ Description : : Ansible is a radically simple model-driven configuration management, : multi-node deployment, and remote task execution system. Ansible works : over SSH and does not require any software or daemons to be installed : on remote nodes. Extension modules can be written in any language and   : are transferred to managed machines automatically. [root@localhost tmp]# [root@localhost tmp]# sudo yum install ansible : : [root@localhost tmp]# ansible --version ansible 1.9.4     configured module search path = None **很好... 准备开始!** ## Ansible 方面 关于不同的 Ansible 组件(清单、Playbook、模块、角色等)的用法,应查看 Ansible 文档。 为了简化管理以及避免使用大而复杂的脚本文件,使用了预定义的目录结构和搜索路径。 在本帖中,我将使用一个采用 Ansible 建议的文件结构,当您考虑构建更大的安装示例时,可以将本结构用作模型。 所使用的 Ansible 模块带有注释和自我说明,可以在 Github 上获取。 下载文件并通读以了解工作流程。 我们的示例的基本目录包含以下文件; * ansible.cfg:对 Ansible 默认值的更改。 * 清单:定义和描述工作环境。 例如服务器名称/IP。 * <各种>.yml 文件:这些文件描述了将为特定服务器角色运行的任务集。 ### 术语 为了使后面的讨论更清晰,下面是一些 Ansible 术语的快速解释。 模块是用于创建对系统执行的自动化操作的构建块。 每个模块都为特定任务构建,可以使用参数更改该任务。 例如复制文件、创建用户、运行命令、启动服务等。 目前,默认的 Ansible 安装已包含 400 多个模块,另外还有更多来自社区的模块,您也可以创建您自己的模块。 模块组合在一起生成 play 和 playbook,作为执行自动化工作流程的一种方式。 一个 Play 可以有多个任务,一个 Playbook 可以有多个 Play。 角色允许您组合 Playbook。 角色可以被视为根据目标服务器使用情况分组在一起的服务器组件配置。 在本帖的示例中,角色构建配置层以构建服务器。 在我的基准测试设置中,我有以下角色来构建服务器: * hs\_server\_common:配置操作系统,安装 Apache,安装 Caché。 *  webserver:复制 Web 文件(csp、html、js 等),针对应用程序配置 Apache。 * generator:复制文件,创建和配置 webstress 生成器数据库、命名空间、全局映射等。 * dbserver:复制文件,配置数据库服务器系统设置、应用程序数据库、命名空间、全局映射等。 可以组合这些角色来构建不同的服务器类型: * hs\_server\_common + webserver + generator = webstress 生成器服务器。 * hs\_server\_common + webserver = 应用程序 Web 服务器。 * hs\_server\_common + dbsevrer = 数据库服务器。 角色的组成以及每个角色中包含的配置将非常特定于要部署的应用程序。 本帖中的示例将使用最小的任务集,并假定操作系统已预先配置,但是,使用 Ansible 和 Galaxy 上的模块可以实现更复杂和全功能的系统配置。 ## 关于安装 Caché 的说明 {.MsoNormal} 我写了几个例子来介绍一些有趣和有用的特性,下面是一些精华部分。 注意:这些示例可以用作 InterSystems 数据平台(Caché、HealthShare 和 Ensemble)的安装指南。 我写的示例是安装 HealthShare,但 HealthShare 和 Caché 示例中的操作是相同的。 **./testserver/roles/hs\_server\_common/tasks/main.yml** 这是配置操作系统、安装 Apache、安装 Caché 等常见任务的主线脚本。 本帖中对其进行了删减,使其只包含用于 Red Hat 的文件,以及只安装和配置 Caché。 您可以看到,Ansible 在启动后已经在 _ansible_*_ 变量(包括 _ansible\_os\_family_)中保存了操作系统信息,我们可以在脚本中使用这些变量做出决策。 **./testserver/roles/hs\_server\_common/tasks/configure-healthshare2015.yml** 这是用于安装 Caché 的主脚本。 浏览该脚本,会看到针对目标执行的任务的逻辑工作流程,包括: * 创建操作系统用户和组。 * 从控制器上的清单文件夹复制安装文件。 * 解压缩安装文件。 * 使用静默安装方式安装 Caché(请参见下面的注释)。 * 复制 Caché 密钥文件 * 设置默认 Caché 实例 * 重启 Apache * 重启 Caché Caché 的静默安装有几个选项,包括: * 使用 parameters.is 文件。 模板 .isc 文件由以前的安装创建,可以按原样使用,也可以修改。 * 使用 cinstall_silent 以及环境中设置的键值对。 * 使用 %installer 类。 在此示例中,我选择了使用 install\_silent,但是我还包括了一个注释掉的使用参数文件的备用方法,以说明如何在 Ansible 中使用模板文件(请参见 /roles/hs\_server\_common/templates/parameters\_hs20152_rh64.isc)。 在以后的帖子中,我将说明如何使用 %installer 类安装 Caché 以及设置数据库和命名空间。 有关安装选项的详细信息,请参见 Caché 在线文档,社区中也有一个非常好的帖子介绍了 %installer 类的使用。 当您想要安装并配置 Caché,以将 CSPGateway 与除了旧版本 Caché 内部的 Apache 版本以外的 Web 服务器一起使用时,参数文件很有用。 自 Caché 2016.1 起,%installer 提供此功能。 **./testserver/roles/hs\_server\_common/tasks/setup_RedHat.yml** 包含此示例是为了说明如何使用系统特定变量 (ansible_*) 和设置操作系统变量。 **./testserver/roles/hs\_server\_common/vars/*** 变量文件包含键:值对形式的变量,如您所见,这是一种在不同环境和情况下重复使用相同脚本的方法。 ## 运行 Caché 安装 对于此示例,我假定系统可用,并按如下方式进行设置。 1. 控制器已安装 Ansible,并且以下目录填充了来自 Github 的文件和结构。 * **./testserver/***:包含清单、.yml 文件等等的目录树。 包括... * **./testserver/Distribution_Files/Cache**:(包含 Caché 分发包和 cache.key 的清单)。 2. 目标机器已安装 Red Hat 和 Apache。 您需要编辑以下文件来为您的测试环境自定义安装。 1. **inventory_test** 您需要编辑测试服务器名称或 IP 地址。 2. .**/testserver/roles/hs\_server\_common/vars/healthshare2015.yml** 您必须编辑路径以适合您的测试环境。 查看目标服务器的以下路径: * **common\_install\_base_path**:清单文件将复制到该位置后解压,并运行 Caché 安装。 * **ISC\_PACKAGE\_INSTALLDIR**:Caché 安装目录 如果目标服务器上不存在这些目录路径,将会创建。 注:自动化部署的特性之一是并行构建多个服务器。 如果清单文件中有多个服务器,在各个目标服务器上将并发运行每个步骤,直至该步骤完成,然后再在组中的每个服务器上开始下一个步骤。 如果任何服务器上有步骤失败,脚本将停止。 您将看到一条错误消息,帮助您更正问题。 更正错误后,只需从头重新运行 — 这是脚本的一个关键特性 — 脚本设计成幂等。 幂等的意思是,在某个步骤运行某个模块(例如复制文件)时,如果文件已经存在,则该步骤不会重新运行,脚本只是继续下一个步骤。 copy 之类的模块有参数可以设置为强制复制,但这不是默认设置。 仔细检查脚本会发现,在某些情况下使用了“creates”参数,例如:   - name: unattended install of hs using cinstall_silent shell: > ISC_PACKAGE_INSTANCENAME="{{ ISC_PACKAGE_INSTANCENAME }}" ISC_PACKAGE_INSTALLDIR="{{ ISC_PACKAGE_INSTALLDIR }}" ISC_PACKAGE_UNICODE="{{ ISC_PACKAGE_UNICODE }}" ISC_PACKAGE_INITIAL_SECURITY="{{ ISC_PACKAGE_INITIAL_SECURITY }}" ISC_PACKAGE_MGRUSER="{{ ISC_PACKAGE_MGRUSER }}" ISC_PACKAGE_MGRGROUP="{{ ISC_PACKAGE_MGRGROUP }}" ISC_PACKAGE_USER_PASSWORD="{{ ISC_PACKAGE_USER_PASSWORD }}" ISC_PACKAGE_CACHEUSER="{{ ISC_PACKAGE_CACHEUSER }}" ISC_PACKAGE_CACHEGROUP="{{ ISC_PACKAGE_CACHEGROUP }}" ./cinstall_silent chdir="{{ common_install_base_path }}/{{ hs_install_unpack_path }}" args: creates: "{{ ISC_PACKAGE_INSTALLDIR }}/cinstall.log" 上面一节使用 creates 参数告诉 Ansible 模块(在本例中是 shell 模块),此操作创建 cinstall.log 文件。 如果模块发现该文件(Caché 已经安装),则此步骤将不会运行。 好了,全部设置完毕后,我们可以运行安装了。 $ ansible-playbook dbserver.yml PLAY [dbservers] ************************************************************** GATHERING FACTS *************************************************************** ok: [db1] TASK: [hs_server_common | include_vars healthshare2015.yml] ******************* ok: [db1] TASK: [hs_server_common | include_vars os-RedHat.yml] ************************* ok: [db1] etc etc etc TASK: [hs_server_common | Create default cache group] ************************* changed: [db1] TASK: [hs_server_common | Create default cache manager group] ***************** changed: [db1] TASK: [hs_server_common | Create default cache user] ************************** changed: [db1] TASK: [hs_server_common | Create default cache system users] ****************** changed: [db1] TASK: [hs_server_common | Create full hs install temp directory] ************** changed: [db1] TASK: [hs_server_common | Check tar file (gunzipped already) does not exist] *** ok: [db1] TASK: [hs_server_common | Copy healthshare install file] ********************** changed: [db1] TASK: [hs_server_common | un zip hs folder] *********************************** changed: [db1] TASK: [hs_server_common | un tar hs install] ********************************** changed: [db1] TASK: [hs_server_common | Create hs install directory] ************************ changed: [db1] TASK: [hs_server_common | touch ztrak.conf.] ********************************** changed: [db1] TASK: [hs_server_common | Process parameters file] **************************** changed: [db1] TASK: [hs_server_common | unattended install of hs using cinstall_silent] ***** changed: [db1] TASK: [hs_server_common | copy hs key] **************************************** changed: [db1] TASK: [hs_server_common | Set default hs instance] **************************** changed: [db1] TASK: [hs_server_common | restart apache to initialize CSP.ini file] ********** changed: [db1] NOTIFIED: [hs_server_common | restart healthshare] **************************** changed: [db1] PLAY RECAP ******************************************************************** db1 : ok=32 changed=21 unreachable=0 failed=0 如果我们查看目标服务器 — 数据库服务器 Caché 现在已经启动并运行。 $ ccontrol list Configuration 'H2015' (default) directory: /test/hs2015 versionid: 2015.2.1.705.0 conf file: cache.cpf (SuperServer port = 1972, WebServer = 57772) status: running, since Wed Feb 17 15:59:11 2016 state: ok ## 总结 在后续的帖子中,我将构建包含其他任务的脚本,如编辑配置文件和使用 %installer 类配置应用程序。 如果您对此感兴趣并开始创建您自己的部署,请随时与我联系,提出问题或建议。 我经常在全球峰会上发表关于虚拟化和性能的演讲 - 因此,如果您参加今年的全球峰会,请介绍一下您自己,我非常乐意和您聊一聊 Ansible 的使用经验或任何其他系统架构话题。
文章
Michael Lei · 六月 23, 2021

Yape - 另一个 pButtons 提取程序(自动创建图表)

> 注(2019 年 6 月):许多内容发生了变化,[最新的详细信息请参见此处](https://community.intersystems.com/post/unpacking-pbuttons-yape-update-notes-and-quick-guides) > 注(2018 年 9 月):自本帖首次发布以来,内容已经有了很大改动,我建议使用 Docker 容器版本,以容器形式运行的项目以及详细信息仍然在 [GitHub 的同一个地址发布](https://github.com/murrayo/yape),您可以下载、运行并根据需要进行修改。 与客户合作进行性能评估、容量规划和故障排除时,我经常解包和查看来自 pButtons 的 Caché 和操作系统指标。 [我不久前发布了一个帖子,介绍了一个用来解包 pButtons 指标的实用工具](https://community.intersystems.com/post/extracting-pbuttons-data-csv-file-easy-charting)(该实用工具使用 unix shell、perl 和 awk 脚本编写),而不是费力地浏览 html 文件,再将需要绘制的部分剪切并粘贴到 excel 中。 虽然这是一个*有用的省时工具*,但还不够完善... 我还使用脚本自动绘制指标图表,以便快速查看并包含在报告中。 但是,这些绘图脚本不容易维护,并且当需要站点特定的配置(例如 iostat 或 Windows perfmon 的磁盘列表)时会变得特别混乱,所以我从未公开发布过绘图实用工具。 不过我现在可以很高兴地说,已经有了简单得多的解决方案。 当我与 Fabian 一起在客户站点查看系统性能时,有了意外发现,[他向我展示了使用实用的 Python 绘图模块所做的工作](https://community.intersystems.com/post/visualizing-data-jungle-part-i-lets-make-graph)。 这是一个比我使用的脚本更灵活、更容易维护的解决方案。 集成 Python 模块进行文件管理和绘制图表的简便性,包括可以分享的交互式 html,意味着输出可以有更大用处。 以 Fabian 的帖子为基础,我编写了 __Yape__,旨在快速简单地提取客户的多种格式的 pButtons 文件,然后绘制图表。 该项目已[在 GitHub 上发布](https://github.com/murrayo/yape),您可以下载、运行并根据需要进行修改。 ## 概述 目前,此过程有_两个_步骤。 ### 步骤 1. `extract_pButtons.py` 从 pButtons 提取感兴趣的部分并写入到 .csv 文件,以便使用 Excel 打开或使用 `graph_pButtons.py` 进行绘图处理。 ### 步骤 2. `graph_pButtons.py` 绘制步骤 1 中创建的文件的图表。 目前,输出可以是 `.png` 形式的线形图或点阵图,也可以是带有平移、缩放、打印等选项的`交互式 .html`。 GitHub 上的 _Readme.md_ 详细介绍了如何设置和运行这两个 python 脚本,并且将是最新的参考。 ## 其他说明 例如:使用向输出和输入目录添加前缀的选项,可以轻松遍历包含一组(例如一个星期)pButtons html 文件的目录,并针对每个 pButtons 文件都输出到一个单独目录。 for i in `ls *.html`; do ./extract_pButtons.py $i -p ${i}_; done for i in `ls *.html`; do ./graph_pButtons.py ./${i}_metrics -p ${i}_; done 在短期内,当我继续撰写有关 [Caché 容量规划和性能](https://community.intersystems.com/post/intersystems-data-platforms-capacity-planning-and-performance-series-index)的系列文章时,我将使用由这些实用工具创建的图表。 我已经在 OSX 上进行了测试,但没有在 Windows 上测试。 您应该能够在 Windows 上安装和运行 Python,请留下您在 Windows 下的经验反馈。 例如,我猜想必须对文件路径斜杠进行更改。 > 注:直到几周前,我都没有用 Python 编写过任何东西,所以如果您是 Python 专家,那么代码中可能会有一些内容并不是最佳做法。 但是,我几乎每天都使用这些脚本,因此我将继续进行改进。 我希望我的 Python 技能会有所提高 — 但是如果您看到一些应该纠正的地方,请随意“教导”我! 如果您发现这些脚本有用,请告诉我,并不时回来看看以获取新功能和更新。
文章
Michael Lei · 六月 23, 2021

最低限度的监控和警报解决方案

InterSystems 数据平台包括了用于系统监视和警报的实用程序及工具,但对于不熟悉构建于 InterSystems 数据平台(又名 Caché)的解决方案的系统管理员来说,他们需要知道从何处下手以及需要配置什么。 本指南以在线文档和开发者社区帖子为参考,介绍了实现最低限度的监视和警报解决方案的途径,以及如何启用和配置以下组件: 1. **Caché Monitor:**扫描控制台日志并发送电子邮件警报。 2. **System Monitor:**监视系统状态和资源,根据固定参数生成通知(警报和警告),同时跟踪整体系统运行状况。 3. **Health Monitor:**对主要的系统和用户定义指标进行采样,并将它们与用户可配置的参数和既定的标准值进行比较,在样本超过适用或学习的阈值时生成通知。 4. **History Monitor:**维护性能指标和系统使用情况指标的历史数据库。 5. **pButtons:**每天按计划收集操作系统指标和 Caché 指标。 请记住,本指南是最低配置,所包含的工具灵活且可扩展,因此可在需要时提供更多功能。 本指南跳过了文档,让您直接上手。 您需要更深入地研究文档才能充分利用监视工具,同时,请考虑将本指南作为启动和运行的速查表。 ---- # 1. Caché Monitor 控制台日志 `(install-directory/mgr/cconsole.log)` 必须被监视,可以通过第三方工具扫描日志文件,或者像我们这样使用附带的 Caché Monitor 实用工具将警报发送到一个电子邮件地址。 控制台日志是其他监视工具(包括 Caché System Monitor 和 Caché Health Monitor)用于编写警报和通知的中央存储库。 > 至少将 Caché Monitor 配置为向一个电子邮件发送警报。 使用 ^MONMGR 实用工具管理 Caché Monitor。 ## Caché Monitor 基本设置 Caché Monitor 扫描控制台日志,并根据可配置的消息严重级别生成通知。 通知通过电子邮件发送到您配置的收件人列表。 默认扫描周期为每 10 秒一次,但可以更改。 > 提示:将 Caché Monitor 警报严重级别配置为 1(警告、严重和致命条目)。 如果您发现收到的警报太多,可以降回到警报级别 2(严重和致命条目)。 当 60 秒内有一系列条目来自一个给定进程时,只会针对第一个条目生成通知,然后暂停一小时。 因此,当出现问题时,必须进行调查。 因为没有新消息并不表示事件已过去。 此规则的例外是 [Caché Monitor 错误和陷阱](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_monitor#GCM_monitor_errors)中列出的控制台日志条目,会针对其中所有条目生成通知。 [有关完整的配置详细信息,请参见 ^MONMGR 的在线文档。](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_monitor#GCM_monitor_errors) ## Caché Monitor 速查表 启用 Caché Monitor 不需要很多操作。 确保 Monitor 已启动,然后设置电子邮件选项。 %SYS>d ^MONMGR 1) Start/Stop/Update MONITOR 2) Manage MONITOR Options 3) Exit Option? **1** 1) Update MONITOR 2) Halt MONITOR 3) Start MONITOR 4) Reset Alerts 5) Exit Option? **3** Starting MONITOR... MONITOR started 1) Update MONITOR 2) Halt MONITOR 3) Start MONITOR 4) Reset Alerts 5) Exit Option? **** 设置警报严重级别。 1) Start/Stop/Update MONITOR 2) Manage MONITOR Options 3) Exit Option? **2** 1) Set Monitor Interval 2) Set Alert Level 3) Manage Email Options 4) Exit Option? **2** Alert on Severity (1=warning,2=severe,3=fatal)? 2 => **1** 设置电子邮件选项,您可能需要联系 IT 部门以获取电子邮件服务器的地址。 任何有效的电子邮件地址都应该可用。 1) Set Monitor Interval 2) Set Alert Level 3) Manage Email Options 4) Exit Option? **3** 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authentication 6) Test Email 7) Exit Option? 确保在设置后测试电子邮件(选项 6)。 ## Caché Monitor 示例 Caché System Monitor 针对高 CPU 利用率生成了一个严重级别为 2 的条目,该条目已发送到 cconsole.log: 03/07/18-11:44:50:578 (4410) 2 [SYSTEM MONITOR] CPUusage Alert: CPUusage = 92, 95, 98 (Max value is 85). 同时也向 Caché Monitor 电子邮件收件人发送了一封电子邮件,其内容与 console.log 相同,主题行为: [CACHE SEVERE ERROR yourserver.name.com:instancename] [SYSTEM MONITOR] CPUusage Alert: CPUusage = 92, 95, 98 (Max value is 85). ## Caché Monitor 更多提示 在开发者社区的另一篇文章的评论中,Aric West 提示可以在发件人电子邮件中嵌入更多信息,例如,不要只设置一个有效的电子邮件,而是将发件人或收件人设置为:"某个名字" \ ---- # Caché System Monitor 工具 Caché System Monitor 是一系列监视工具的汇总,通过 `^%SYSMONMGR` 实用工具进行配置。 如简介中所述,为实现最低限度的监视解决方案,我们将配置: - System Monitor - Health Monitor - History Monitor 顺带说一下,是的,名称 _System Monitor_ 很令人烦恼地重载了其父名称 _Caché System Monitor_。 Caché System Monitor 和 Health Monitor 通知和警报会发送到控制台日志,使 Caché Monitor(在上一节中设置)可以在事件发生时生成电子邮件。 [有关 Caché System Monitor 的所有深入详细信息,请参见在线文档。](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_healthmon) ---- **警告说明:**您还将在 ^%SYSMONMGR 菜单中看到 **Application Monitor**。 本指南中不会配置 Application Monitor。 本指南中介绍的工具和实用程序对系统性能的影响可以忽略不计,然而 Application Monitor 有一些类是此规则的例外。 [有关详细信息,请参见 ^PERFMON 实用工具的文档](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_perfmon)。 如果您使用 Application Monitor,则必须先在非生产系统上测试,因为运行任何时长的 ^PERFMON 都可能对性能产生重大影响。 ---- # 2. System Monitor 根据文档:“System Monitor 对重要的系统状态和资源使用指标(例如 ECP 连接的状态和使用中的锁表的百分比)进行采样,并根据固定状态和阈值生成通知(警报、警告和‘状态正常’消息)”。 [文档中有 System Monitor 状态和资源指标](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_healthmon_sysmon_alerts)的列表。 例如:日志空间(日志目录中的可用空间): - 少于 250 MB = _警告_ - 少于 50 MB = _警报_ - 警告/警报后大于 250 MB = _正常_ ## System Monitor 基本设置 System Monitor 警报和警告会写入控制台日志,因此请确保 Caché Monitor 设置为发送电子邮件警报(上一节)。 使用 ^SYSMONMGR 实用工具管理 System Monitor。 默认情况下,当实例运行时,System Monitor 也一直运行;可以使用 ^%SYSMONMGR 将其停止,但是当实例下次启动时,它会自动再次启动。 默认情况下,System Monitor 具有以下可以更改的设置: - 每 30 秒获取一次传感器指标。 - 仅将警报、警告和消息写入 System Monitor 日志。 System Monitor 还维护单一整体系统运行状况状态,当运行 `ccontrol list` 等命令时可以查询或使用该状态: - 绿色(正常) - 黄色(警告) - 红色(警报) ### System Monitor 速查表 对于最低限度的监视解决方案,实际上无需任何操作,因为当实例运行时,它也一直运行。 ---- # 3. Health Monitor 根据文档:“Caché Health Monitor 通过在特定期间对一系列关键指标的值进行采样,并将这些值与配置的指标参数和这些期间的既定标准值进行比较,来监视正在运行的 Caché 实例;如果采样值过高,Health Monitor 将生成警报或警告。 例如,根据配置的 CPU 使用率最大值或者在星期一上午 9:00 至 11:30 期间采集的标准 CPU 使用率样本,如果 Health Monitor 在星期一上午 10:15 采样的 CPU 使用率过高,Health Monitor 将生成通知。” [Health Monitor 对 41 个系统传感器进行采样,文档中给出了列表和默认值。](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_healthmon#GCM_healthmon_overview_api_sensors) Health Monitor 警报(严重级别 2)和警告(严重级别 1)将写入控制台日志。 Health Monitor 生成: - 警报,如果在一个期间内传感器的三次连续读数大于传感器最大值。 - 警告,如果在一个期间内传感器的五次连续读数大于传感器警告值。 对于为最大值或警告值设置了条目的传感器,即使 Health Monitor 本身未启用,也会立即生成警报。 例如,为 CPU 配置的最大值为 85,警告值为 75,所以当连续 5 次的 CPU 利用率测量值超过 75% 时,会将以下通知发送到控制台日志: 1 [SYSTEM MONITOR] CPUusage Warning: CPUusage = 83 ( Warnvalue is 75). 其他传感器需要收集足够长时间的指标才能创建_图表_。 需要图表来评估指标的平均值,从而得出标准偏差 (sigma),以便在值超出正常范围时发出警报。 在一个_期间_内收集指标。 有 63 个标准期间,一个期间示例是星期一上午 9:00 至 11:30。 期间可以更改。 ## Health Monitor 基本设置 > Health Monitor 不会自动启动,需要使用 ^%SYSMONMGR 中的设置来启用它。 默认情况下,Health Monitor 在 Caché 启动后等待 10 分钟,以便系统达到正常运行状态,如果需要,可以更改此时间。 Caché Health Monitor 传感器对象带有默认值。 例如,如上文所述,_CPUPct_(系统 CPU 使用率百分比)的默认值为:基础值 50,最大值 90,警告值 80。 您可能更保守一些,并想要更改这些值,使用 ^%SYSMONMGR 可以更改这些值,例如,最大值 85,警告值 70。 现在,当 CPU 使用率达到 99% 时,我们会看到: 2 [SYSTEM MONITOR] CPUusage Alert: CPUusage = 99, 99, 99 (Max value is 85). ## Health Monitor 速查表 该速查表相当长,显示在总结后面。 ---- # 4. History Monitor [David Loveluck 在社区上有一个非常好的帖子。](https://community.intersystems.com/post/apm-using-cach%C3%A9-history-monitor)按照该帖中的说明启动 History Monitor,开始收集和评估指标。 ---- # 5. pButtons pButtons 实用工具可根据其创建的日志文件生成可读的 HTML 性能报告,其中包含操作系统和 Caché 指标。 pButtons 输出的性能指标可以被提取、绘图和评估。 例如,一天中 CPU 利用率或 Caché 数据库访问量的图表。 每天 24 小时运行 pButtons 收集是一种简单但至关重要的方法,用于收集指标以进行故障排除。 pButtons 对于趋势分析也非常有用。 以下社区文章详细介绍了 pButtons 以及如何将其计划为每天运行:[InterSystems 数据平台和性能 – 第 1 部分](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-%E2%80%93-part-1) > 如文章中所述,30 秒收集间隔对于趋势分析和 24 小时报告是合适的。 还有说明用于确保您即使没有运行最新版的 Caché,也能拥有最新版的 pButtons:[InterSystems 数据平台和性能 – 如何更新 pButtons](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-%E2%80%93-how-update-pbuttons)。 虽然 pButtons 主要是一个支持工具,但您可以通过快速绘制所收集的指标来获得宝贵的系统使用情况洞察:[Yape - 另一个 pButtons 提取程序(自动创建图表)](https://community.intersystems.com/post/yape-yet-another-pbuttons-extractor-and-automatically-create-charts) ---- # 总结 本帖仅触及了监控选项的皮毛,例如 Health Monitor 将以默认设置工作,但随着时间的推移,您将希望探索可自定义的选项来满足您的应用程序配置文件。 ## 接下来的方向? 如我们所见,我们将 System Monitor 和 Health Monitor 实用工具配置为将警报发送到作为中央报告位置的 cconsole.log。 我们使用了 Caché Monitor 将这些警报发送到电子邮件。 有一些第三方工具可以抓取日志并消耗非结构化的日志数据,您可能已经在组织中使用这些工具,而且也没有理由不使用它们。 如今,我看到许多客户在 VMware 上进行虚拟化。 如果您使用 vSphere,请考虑使用 Log Insight 来监视控制台日志。 在撰写本帖时(2018 年 3 月),对于您拥有的每个 vCenter Server 6.0 实例,您都有资格获取一个免费的 vRealize Log Insight for vCenter 25 OSI 许可证。 Log insight 是一个读取非结构化数据的工具,用于日志管理和分析 — 例如,您可以将其与 cconsole.log 配合使用 — 如果您对此感兴趣,请联系 VMware 以了解更多信息。 同时,我正计划在将来的帖子中展示如何将 Log Insight 与 cconsole.log 配合使用。 ---- 如果您在收集指标,您仍然需要研究它们,并了解他们的含义,我将继续发帖来展示如何解释所呈现的信息,特别是性能指标。 ---- # 应用程序性能监视 David Loveluck 在社区中有一系列关于应用程序性能监视的帖子,请在社区中搜索 APM,或者[从这里开始](https://community.intersystems.com/post/what-apm)。 ---- ## 附录:Health Monitor 速查表 本速查表展示了我们在第 3 节看到的 Health Monitor 的启动过程,并完成了传感器阈值的编辑。 首先让我们启动 Health Monitor。 %SYS>**d ^%SYSMONMGR** 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? **6** 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? **1** Enable Health Monitor? No => **yes** Health Monitor is Enabled. Stop and restart System Monitor to run Health Monitor 如我们从消息中所见,导航回到第一个菜单或再次启动 ^%SYSMONMGR 来停止 System Monitor 并再次启动它,以完成这一过程。 %SYS>**d ^%SYSMONMGR** 1) Start/Stop System Monitor 2) Set System Monitor Options etc... 我们将在这里继续,以编辑 CPUPct 阈值为例。 %SYS>**d ^%SYSMONMGR** 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? **6** 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? **3** 1) Activate/Deactivate Rules 2) Configure Periods 3) Configure Charts 4) Edit Sensor Objects 5) Reset Defaults 6) Exit Option? **4** 先看一下所有传感器; 1) List Sensor Objects 2) Edit Sensor Object 3) Exit Option? **1** Sensor Base Max Max M Warn Warn M -- ---- --- ----- ---- ------ CPUPct 50 80 0 70 0 CPUusage 50 85 0 75 0 CSPActivity 100 0 2 0 1.6 : : : WDWIJTime 60 0 2 0 1.6 WDWriteSize 1024 0 2 0 1.6 1) List Sensor Objects 2) Edit Sensor Object 3) Exit Option? **2** Cannot configure while System Monitor is running. 1) List Sensor Objects 2) Edit Sensor Object 3) Exit 噢,我们需要先返回并禁用 Health Monitor 和 System Monitor。 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? **1** Disable Health Monitor? No => **yes** Health Monitor is Disabled. Stop and restart System Monitor to halt Health Monitor 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option?**** 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? **1** 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? **2** Stopping System Monitor... System Monitor stopped 好了,Health Monitor 和 System Monitor 已停止。 现在导航回到 Health Monitor 并编辑一个传感器对象。 1) Start System Monitor 2) Stop System Monitor 3) Exit Option?**** 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? **6** 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? **3** 1) Activate/Deactivate Rules 2) Configure Periods 3) Configure Charts 4) Edit Sensor Objects 5) Reset Defaults 6) Exit Option? **4** 1) List Sensor Objects 2) Edit Sensor Object 3) Exit Option? **2** 输入传感器名称(如果您知道的话),否则输入“?”以显示列表。 传感器? **?** Num Sensor Threshold 1) CPUPct 2) CPUusage : : : 46) WDWIJTime 47) WDWriteSize Sensor? **1** CPUPct Base? 50 =>**** Enter either an Alert Value or a Multiplier Alert Value? 80 => **85** Setting Max Multiplier and Warn Multiplier to 0. Enter a Warn Value Warn Value? 70 => **75** Sensor object CPUPct updated. Base 50 MaxMult 0 AlertValue 85 WarnMult 0 WarnValue 75 1) List Sensor Objects 2) Edit Sensor Object 3) Exit 现在返回并启用 Health Monitor 和启动 System Monitor。 Option?**** 1) Activate/Deactivate Rules 2) Configure Periods 3) Configure Charts 4) Edit Sensor Objects 5) Reset Defaults 6) Exit Option?**** 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? **1** Enable Health Monitor? No => **yes** Health Monitor is Enabled. Stop and restart System Monitor to run Health Monitor 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option?**** 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? **1** 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? **1** Starting System Monitor... System Monitor started 好了,工作已完成! ----
公告
Claire Zheng · 六月 22, 2021

畅聊吧!来Discord加入InterSystems开发者社区!

亲爱的社区开发者们,大家好! 你可能已经听说过Discord,很多人或许已经是Discord的资深用户了。此刻我们邀请您走近InterSystems技术的世界,加入我们的开发人员社交俱乐部! 用一种超级便捷的方式交流沟通: 💥 Discord:InterSystems开发者社区 💥 在开发者社区Discord Server上, 你会发现许多与intersystems相关的频道和讨论,以及日常生活对话的频道。只要加入我们的俱乐部,就能更接近InterSystems开发者的世界! 约起来,在 Discord:InterSystems开发者社区 与您相聚✌️ 如果您对提升Discord Server有任何建议,或者想在某个特定话题上创建一个新频道,欢迎在评论中分享:)
文章
姚 鑫 · 六月 22, 2021

第十五章 XML检查属性

# 第十五章 XML检查属性 # 检查属性的基本方法 可以使用`%XML.Node`的以下方法。以检查当前节点的属性。 - `AttributeDefined()` 如果当前元素具有具有给定名称的属性,则返回非零(TRUE)。 - `FirstAttributeName()` 返回当前元素的第一个属性的属性名称。 - `GetAttributeValue()` 返回给定属性的值。如果元素没有该属性,则该方法返回NULL。 - `GetNumberAttributes()` 返回当前元素的属性数。 - `LastAttributeName()` 返回当前元素的最后一个属性的属性名称。 - `NextAttributeName()` 在给定属性名称的情况下,无论指定的属性是否有效,此方法都会按排序顺序返回下一个属性的名称。 - `PreviousAttributeName()` 在给定属性名称的情况下,无论指定的属性是否有效,此方法都会按排序顺序返回上一个属性的名称。 下面的示例遍历给定节点中的属性并编写一个简单报表: ```java /// d ##class(Demo.XmlDemo).ShowAttributes("David Marston") /// David Marston ClassMethod ShowAttributes(string) { set reader=##class(%XML.Reader).%New() set status=reader.OpenString(string) if $$$ISERR(status) {do $System.Status.DisplayError(status)} s node = reader.Document.GetDocumentElement() b s count = node.GetNumberAttributes() w !, "属性数量: ", count s first = node.FirstAttributeName() w !, "第一个属性是: ", first w !, " 值是: ",node.GetAttributeValue(first) s next = node.NextAttributeName(first) for i = 1 : 1 : count - 2 { w !, "下一个属性是: ", next w !, " 值是: ",node.GetAttributeValue(next) s next = node.NextAttributeName(next) } s last = node.LastAttributeName() w !, "最后一个属性是: ", last w !, " 值是: ",node.GetAttributeValue(last) } ``` 示例XML文档: ```xml David Marston ``` 如果将此文档的第一个节点传递给示例方法,则会看到以下输出: ```java Number of attributes: 5 First attribute is: attr1 Its value is: first Next attribute is: attr2 Its value is: second Next attribute is: attr3 Its value is: third Next attribute is: attr4 Its value is: fourth Last attribute is: attr5 Its value is: fifth ``` # 检查属性的其他方法 本节讨论可用于获取任何属性的名称、值、命名空间、`QName`和值命名空间的方法。这些方法分为以下几组: - 仅使用属性名称的方法 - 使用属性名称和命名空间的方法 注意:在XML标准中,一个元素可以包含多个同名的属性,每个属性位于不同的名称空间中。但是,在InterSystems IRIS XML中,这是不受支持的。 ## 仅使用属性名称的方法 使用以下方法获取有关属性的信息。 ### GetAttribute() ```java method GetAttribute(attributeName As %String, ByRef namespace As %String, ByRef value As %String, ByRef valueNamespace As %String) ``` 返回给定属性的数据。此方法通过引用返回下列值: - `Namespace`是来自属性QName的命名空间URI - `value` 是属性值。 - `valueNamespace` 值所属的命名空间URI。例如,以下属性: ``` xsi:type="s:string" ``` 此属性的值为字符串,并且此值位于使用前缀s在其他位置声明的命名空间中。假设本文档的较早部分包含以下命名空间声明: ```java xmlns:s="http://www.w3.org/2001/XMLSchema" ``` 在本例中,`valueNamespace`将为`“http://www.w3.org/2001/XMLSchema”`. ### GetAttributeNamespace() ```java method GetAttributeNamespace(attributeName As %String) as %String ``` 从当前元素的名为`AttributeName`的属性的`QName`返回命名空间URI。 ### GetAttributeQName() ```java method GetAttributeQName(attributeName As %String) as %String ``` 返回给定属性的`QName`。 ### GetAttributeValue() ```java method GetAttributeValue(attributeName As %String) as %String ``` 返回给定属性的值。 ### GetAttributeValueNamespace() ```java method GetAttributeValueNamespace(attributeName As %String) as %String ``` 返回给定属性的值的命名空间。 ## 使用属性名和命名空间的方法 要同时使用属性名称及其命名空间来获取有关属性的信息,请使用以下方法: ### GetAttributeNS() ```java method GetAttributeNS(attributeName As %String, namespace As %String, ByRef value As %String, ByRef valueNamespace As %String) ``` 返回给定属性的数据,其中`AttributeName`和`Namespace`指定感兴趣的属性。此方法通过引用返回以下数据: - `value` 是属性值。 - `valueNamespace` 值所属的命名空间URI。例如,以下属性: ```java xsi:type="s:string" ``` 此属性的值为字符串,并且此值位于使用前缀s在其他位置声明的命名空间中。假设本文档的较早部分包含以下命名空间声明: ```java xmlns:s="http://www.w3.org/2001/XMLSchema" ``` ### GetAttributeQNameNS() ```java method GetAttributeQNameNS(attributeName As %String, namespace As %String) as %String ``` 返回给定属性的`QName`,其中`AttributeName`和`Namespace`指定感兴趣的属性。 ### GetAttributeValueNS() ```java method GetAttributeValueNS(attributeName As %String, namespace As %String) as %String ``` 返回给定属性的值,其中`AttributeName`和`Namespace`指定感兴趣的属性。 ### GetAttributeValueNamespaceNS ```java method GetAttributeValueNamespaceNS(attributeName As %String, namespace As %String) as %String ``` 返回给定属性的值的命名空间,其中`AttributeName`和`Namespace`指定感兴趣的属性。
文章
TZ Zhuang · 六月 22, 2021

FAQ 常见问题系列--系统管理篇 每个InterSystems IRIS实例可以创建多少个数据库和命名空间

一个实例中可创建的最大命名空间数量为2048个。这个上限不可修改。 一个实例中可创建的最大数据库数量(包括远程数据库)为15998个。这个上限也不可修改。 一个实例中可创建数据库的总数量还有其他因素制约: 1. 数据库路径信息总量最大为256KB,也就是所有数据库的路径字符加起来不能多于256KB。设置的路径越长,可创建的数据库数量越少。计算公式:最大数据库数量=258048/(平均数据库路径长度+3) 2. 镜像的数据库一个按两个算。也就是创建一个镜像的数据库,相当于创建了2个非镜像数据库。 更多细节请参考在线文档:https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GSA_config
问题
xu hui · 六月 22, 2021

ERROR [HYT00] [Cache ODBC][State : HYT00][Native Code 450] [c:\windows\system32\inetsrv\w3wp.exe] Request timed out due to user timeout

我在用.net通过ODBC连接cache数据库,OdbcConnection connection = new OdbcConnection(dbConnection);connection.Open();打开链接时报这错,请教大佬们,这应该怎么解决吗?不胜感激! 您好!该问题请提交WRC服务 您可以登录网址:https://wrc.intersystems.com提交 第一个问题, 你是连本机还是远程?第2个问题, 你有没有测windows操作系统的cache odbc连接? 您好,非常感谢您的回复。我连接的是局域网内的其他远程服务器;我用同样的代码连接windows操作系统的DSN,是可以connection.Open();运行到这步并进行下去的。请问还有可能是什么原因吗?万分感谢@ 好的,初来乍到,不懂流程,抱歉。但我登录您所给的网址,提示 is not enabled for WRC login. If this is unexpected, please contact InterSystems Support.提交不了WRC服务