搜索​​​​

清除过滤器
文章
姚 鑫 · 六月 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服务
文章
姚 鑫 · 六月 21, 2021

第十四章 XML获取当前节点信息

# 第十四章 XML获取当前节点信息 # DOM节点类型 `%XML.Document`和`%XML.Node`类识别以下`DOM`节点类型: - Element (`$$$xmlELEMENTNODE`) 请注意,这些宏在%xml.DOM.inc包含文件中定义。 - Text (`$$$xmlTEXTNODE`) - Whitespace (`$$$xmlWHITESPACENODE`). 其他类型的`DOM`节点被简单地忽略。 请以下XML文档: ```xml Jack O'Neill Samantha Carter Daniel Jackson ``` 当作为DOM查看时,该文档由以下节点组成: 文档节点示例 NodeID| NodeType |LocalName| Notes ---|---|---|--- 0,29| `$$$xmlELEMENTNODE`| team | 1,29| `$$$xmlWHITESPACENODE`| | 该节点是``节点的子节点 1,23| `$$$xmlELEMENTNODE`| member| 该节点是``节点的子节点 2,45| `$$$xmlTEXTNODE`| Jack O'Neill| 该节点是第一个``节点的子节点 1,37| `$$$xmlWHITESPACENODE`| | 该节点是``节点的子节点 1,41| `$$$xmlELEMENTNODE`| member |该节点是``节点的子节点 3,45| `$$$xmlTEXTNODE` |Samantha Carter| 该节点是第二个``节点的子节点 1,45| `$$$xmlWHITESPACENODE`| |该节点是``节点的子节点 1,49| `$$$xmlELEMENTNODE`| member |该节点是``节点的子节点 4,45| `$$$xmlTEXTNODE`| Daniel Jackson| 该节点是第三个``节点的子节点 1,53| `$$$xmlWHITESPACENODE`| |该节点是``节点的子节点 # 获取当前节点信息 `%XML.Node`的以下字符串属性。提供关于当前节点的信息。 在所有情况下,如果没有当前节点,将抛出一个错误。 ### LocalName 当前元素节点的本地名称。如果访问其他类型节点的此属性,则会引发错误。 ### Namespace 当前元素节点的命名空间URI。如果尝试访问其他类型节点的此属性,则会引发错误。 ### NamespaceIndex 当前元素节点的命名空间的索引。 当InterSystems IRIS读取XML文档并创建DOM时,它会标识文档中使用的所有名称空间,并为每个名称空间分配一个索引号。 如果尝试访问其他类型节点的此属性,则会引发错误。 ### Nil 如果`xsi:nil`或`xsi:null`为true,则等于true;如果此元素节点为1,则等于1。否则,此属性等于`False`。 ### NodeData 字符节点的值。 ### NodeId 当前节点ID。 可以设置此属性以导航到另一个节点。 ### NodeType 当前节点的类型,如前一节所述。 ### QName 元素节点的Q名称。仅当前缀对文档有效时才用于输出为XML。 以下方法提供有关当前节点的其他信息: ### GetText() ```java method GetText(ByRef text) as %Boolean ``` 获取元素节点的文本内容。如果返回文本,则此方法返回TRUE;在本例中,实际文本被追加到第一个参数后,该参数通过引用返回。 ### HasChildNodes() ```java method HasChildNodes(skipWhitespace As %Boolean = 0) as %Boolean ``` 如果当前节点有子节点,则返回True;否则返回False。 ### GetNumberAttributes() ```java method GetNumberAttributes() as %Integer ``` 方法`GetNumberAttributes()`为`%Integer` ## 示例 下面的示例方法编写一个报告,提供有关当前节点的信息: ```java ClassMethod ShowNode(node As %XML.Node) { w !,"LocalName=" _ node.LocalName if node.NodeType=$$$xmlELEMENTNODE { w !,"Namespace=" _ node.Namespace } if node.NodeType = $$$xmlELEMENTNODE { w !,"NamespaceIndex=" _ node.NamespaceIndex } w !,"Nil=" _ node.Nil w !,"NodeData=" _ node.NodeData w !,"NodeId=" _ node.NodeId w !,"NodeType=" _ node.NodeType w !,"QName=" _ node.QName w !,"HasChildNodes returns " _ node.HasChildNodes() w !,"GetNumberAttributes returns " _ node.GetNumberAttributes() s status = node.GetText(.text) if status { w !, "该节点的文本为 "_text } else { w !, "GetText不返回文本" } } ``` 示例输出可能如下所示: ```java LocalName=update Namespace= NamespaceIndex= Nil=0 NodeData=update NodeId=0,29 NodeType=0 QName=update HasChildNodes returns 1 GetNumberAttributes returns 0 GetText不返回文本 文档中的命名空间数: 1 Namespace 1 is http://www.w3.org/2001/XMLSchema-instance DHC-APP> ```
公告
Claire Zheng · 六月 20, 2021

InterSystems 开发者竞赛:人工智能与机器学习

亲爱的社区开发者们,大家好! 欢迎积极参与新一轮InterSystems开发者竞赛! 🏆 InterSystems 编程大赛:人工智能与机器学习 🏆 竞赛时间: 2021年6月28日 - 7月25日 奖金总额: $8,750 奖项设置 1. 专家提名奖(Experts Nomination)- 获奖者由我们特别挑选的专家团选出: 🥇 第一名- $4,000 🥈 第二名 - $2,000 🥉 第三名 - $1,000 2. 社区提名奖(Community Nomination)- 获得总投票数最多的应用: 🥇 第一名 - $1,000 🥈 第二名 - $500 🥉 第三名 - $250 如果同时多位参赛者获得同样的票数,均被视为优胜者,将平分奖金。 谁可以参加 任何开发者社区的成员均可参加,InterSystems内部员工除外。还没有账号?现在来建一个! 👥 开发者可以组团 创建一个协作应用程序,组团限定人数为2-5人。 请注意,要在您的README文件中标注您的团队成员——社区用户profile 参赛时间安排 🛠 6月 28日 - 7月18日: 应用开发、提交阶段 ✅ 7月19日 - 7月 25日: 投票阶段 🎉 7月26日: 宣布优胜者! 注意:在整个参赛期间(开发与投票期间,即6月28日-7月25日),开发者可持续编辑、提升其应用 主题 🤖 人工智能与机器学习 🤖 利用InterSystems IRIS开发一个AI/ML解决方案。您的应用程序可以是一个库(library)、包(package)、工具(tool)或任何使用InterSystems IRIS的AI/ML解决方案。 以下是参赛须知: 有效应用程序:100%全新的Open Exchange Apps或已有的应用程序(但有显著提升)。所有参赛者/团队提交的应用程序只有经过我们团队的审核之后才会被批准参赛。 利用InterSystems IRIS构建使用AI/ML功能的应用程序。 该应用应该在 IRIS Community Edition or IRIS for Health Community Edition or IRIS Advanced Analytics Community Edition 上工作。 该应用需开源并在GitHub上发布。 该应用的README文件应为英文,包含安装步骤,并包含视频demo或/和应用程序如何运行的描述。 (如果有),那么InterSystems ObjectScript部分的源代码应该以UDL(而非XML)格式提交, 举例说明。 上述要求可能会按需修订 资源助力 1. 我们建议从以下模板开始: InterSystems IntegragedML template IRIS R Gateway template 2. 数据导入工具 Data Import Wizard CSVGEN - CSV import util CSVGEN-UI - the web UI for CSVGEN 3. 文档 Using IntegratedML 4. 在线资源 Learn IntegratedML in InterSystems IRIS Preparing Your Data for Machine Learning Predictive Modeling with the Machine Learning Toolkit 5. 如何将您的APP提交给大赛:: 如何在InterSystems Open Exchange上发布应用程序 如何把参赛APP提交给大赛 参赛评比 投票规则即将发布,敬请期待! 期待您的精彩提交!加入我们的编程马拉松,赢取大奖! ❗️点击此处,查看 官方竞赛条款解读❗️ 成为社区活跃客户后即可参与投票:https://cn.community.intersystems.com/post/%E5%A6%82%E4%BD%95%E6%9B%B4%E5%A5%BD%E5%9C%B0%E6%88%90%E4%B8%BA%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE%E8%80%85%E6%B4%BB%E8%B7%83%E7%94%A8%E6%88%B7%EF%BC%9F
文章
姚 鑫 · 六月 20, 2021

第十三章 将XML文档表示为DOM

# 第十三章 将XML文档表示为DOM `%XML.Document`类和`%XML.Node`类使可以将任意XML文档表示为DOM(文档对象模型)。然后,可以导航此对象并对其进行修改。还可以创建一个新的DOM并将其添加到其中。 **注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用本书前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。** # 将XML文档作为DOM打开 要打开现有XML文档以用作DOM,请执行以下操作: 1. 创建`%XML.Reader`的实例。 2. 也可以指定此实例的`Format`属性,以指定要导入的文件的格式。 **默认情况下, IRIS假定XML文件为文字格式。如果文件是SOAP编码格式,则必须指明这一点,以便可以正确读取该文件。** 除非使用`Correlate()`和`Next()`,否则此属性无效。 3. 请使用`%XML.Reader`的以下方法之一。 - `OpenFile()` — 打开一个文件。 - `OpenStream()` —打开一个流。 - `OpenString()` — 打开字符串。 - `OpenURL()` — 打开URL。 在每种情况下,都可以选择为该方法指定第二个参数,以重写`Format`属性的值。 4. 访问`Document`属性,它是一个DOM。此属性是`%XML.Document`实例,它提供了可用于查找有关整个文档的信息的方法。例如,`CountNamespace()`返回DOM使用的名称空间总数。 或者,如果流包含XML文档,调用`%XML.Document`的`GetDocumentFromStream()`方法。返回`%XML.Document`的实例。 ## 示例1:将文件转换为DOM 例如,下面的方法读取一个XML文件,并在表示该文档的返回`%XML.Document`的一个实例: ```java ClassMethod GetXMLDocFromFile(file) As %XML.Document { s reader = ##class(%XML.Reader).%New() s status = reader.OpenFile(file) if $$$ISERR(status) {d $System.Status.DisplayError(status) q $$$NULLOREF} s document = reader.Document q document } ``` ## 示例2:将对象转换为DOM 以下方法接受`OREF`,并在表示该对象中返回`%XML.Document`的实例。该方法假定`OREF`是启用XML的类的实例: ```java ClassMethod GetXMLDoc(object) As %XML.Document { //确保这是启用XML的类的实例 if '$IsObject(object){ w "参数不是对象" q $$$NULLOREF } s classname = $CLASSNAME(object) s isxml = $CLASSMETHOD(classname,"%Extends","%XML.Adaptor") if 'isxml { w "参数不是启用XML的类的实例" q $$$NULLOREF } //步骤1-将对象作为XML写入流 s writer = ##class(%XML.Writer).%New() s stream = ##class(%GlobalCharacterStream).%New() s status = writer.OutputToStream(stream) if $$$ISERR(status) {d $System.Status.DisplayError(status) q $$$NULLOREF} s status = writer.RootObject(object) if $$$ISERR(status) {d $System.Status.DisplayError(status) q $$$NULLOREF} //步骤2-从流中提取%XML.Document s status = ##class(%XML.Document).GetDocumentFromStream(stream,.document) if $$$ISERR(status) {d $System.Status.DisplayError(status) q $$$NULLOREF} quit document } ``` # 获取DOM的名称空间 当 IRIS读取XML文档并创建DOM时,它会标识文档中使用的所有名称空间,并为每个名称空间分配一个索引号。 在`%XML.Document`实例提供了以下方法,可以使用这些方法查找有关文档中命名空间的信息: ### CountNamespace() 返回文档中的命名空间数。 ### FindNamespace() 返回与给定命名空间对应的索引。 ### GetNamespace() 返回给定索引的XML命名空间URI。 下面的示例方法显示一个报表,其中显示文档中使用的命名空间: ```java ClassMethod ShowNamespaces(doc As %XML.Document) { s count = doc.CountNamespace() w !, "文档中的命名空间数: "_count for i = 1 : 1 : count { w !, "Namespace "_i_" is "_doc.GetNamespace(i) } } ``` # 导航DOM的节点 要访问文档的节点,可以使用两种不同的技术: - 使用`%XML.Document`实例的`GetNode()`方法。此方法接受一个整数,它指示从1开始的节点号。 - 调用`%XML.Document`实例的`GetDocumentElement()`方法。 此方法返回`%XML.Node`的实例,提供用于访问有关根节点的信息以及移动到其他节点的属性和方法。以下小节提供了有关使用`%XML.Node`的详细信息。 ## 移动到子节点或同级节点 要移动到子节点或同级节点,请使用`%XML.Node`实例的以下方法。: - `MoveToFirstChild()` - `MoveToLastChild()` - `MoveToNextSibling()` - `MoveToPreviousSibling()` 这些方法中的每一个都移动到另一个节点(如方法名称所示)。如果是,则该方法返回TRUE。如果不是,则返回False,焦点与调用该方法之前相同。 这些方法中的每一个都有一个可选参数`skipWhitespace`。如果此参数为真,则该方法将忽略任何空格。`SkipWhitespace`的默认值为false。 ## 移动到父节点 要移动到当前节点的父节点,请使用`%XML.Node`实例的`MoveToParent()`方法。 此方法接受一个可选参数`restrictDocumentNode`。如果此参数为真,则该方法不会移动到文档节点(根)。`restrictDocumentNode`的默认值为False。 ## 移动到特定节点 要移动到特定节点,可以设置`%XML.Node`实例的`NodeId`属性。例如: ```java set saveNode = node.NodeId //..... lots of processing //... // restore position set node.NodeId=saveNode ``` ## 使用id属性 在某些情况下,XML文档可能包括名为`id`的属性,该属性用于标识文档中的不同节点。例如: ```java Jack O'Neill Samantha Carter Daniel Jackson ``` 如果(如本例所示)文档使用名为`id`的属性,则可以使用它导航到该节点。为此,可以使用文档的`GetNodeById()`方法,该方法返回`%XML.Node`的一个实例。(请注意,与大多数其他导航方法不同,此方法可从`%XML.Document`,而不是`%XML.Node`。)
文章
姚 鑫 · 六月 18, 2021

第十一章 重新定义读取器处理相关对象的方式

# 第十一章 重新定义读取器处理相关对象的方式 # 重新定义读取器处理相关对象的方式 当`%XML.Reader`找到与启用了XML的类相关的XML元素时,读取器会调用该类的`XMLNew()`方法,后者又会在默认情况下调用`%New()`。也就是说,当读取器找到相关元素时,它会创建相关类的新对象。新对象由从XML文档读取的数据填充。 可以通过在启用XML的类中(或在自己的自定义XML适配器中)重新定义`XMLNew()`来自定义此行为。例如,此方法可以改为打开该类的现有实例。然后,现有实例接收从XML文档读取的数据。 以下示例显示如何修改`XMLNew()`以使用XML文档中的新数据更新现有实例。 在这两个示例中,为简单起见,我们假设XML文档中的一个节点包含一个ID,我们可以将该ID与类的范围中的ID进行比较。当然,我们可以用其他方式将XML文档与现有对象进行比较。 ## 当`%XML.Reader`调用`XMLNew()`时 作为参考,`%XML.Reader`在两种情况下自动调用`XMLNew()`方法: - `%XML.Reader`在调用`%XML.Reader`的`Next()`方法调用`XMLNew()`。在将XML元素(在外部文档中)与启用了XML的类关联之后,`%XML.Reader` `Next()`方法从文档中获取下一个元素,调用`XMLNew()`创建相应对象的实例,然后将该元素导入到对象中。 - 同样,`%XML.Reader`为相关XML元素的任何对象值属性调用`XMLNew()`。 ## 示例1:修改启用XML的类中的`XMLNew()` ```java 4 Quine,Maria K. 1964-11-14 Hialeah 94999 Vanzetti,Debra B. ... ``` 此文件映射到以下InterSystems IRIS类(部分显示): ```java Class GXML.PersonWithXMLNew Extends (%Persistent, %Populate, %XML.Adaptor) { Parameter XMLNAME = "Person"; /// make sure this is the same as the XMLNAME of the property /// in this class that is of type %XML.Id Parameter NAMEOFEXPORTID As %String = "IRISID"; Property IdForExport As %XML.Id(XMLNAME = "IRISID", XMLPROJECTION = "ELEMENT") [ Private, Transient ]; Property Name As %Name; Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h"); Property Address As GXML.Address; Property Doctors As list Of GXML.Doctor; ``` 在该类中,`IdForExport`属性的用途是在导出该类的对象时将InterSystems IRIS内部ID投影到元素(`IRISID`)。(在此特定示例中,这使我们能够轻松地生成适合导入的文件。类不必包含这样的属性。) `NAMEOFEXPORTID`参数用于指示导出此类对象时用于InterSystems IRIS ID的元素。包含这一点只是为了方便自定义的`XMLNew()`方法,我们也将该方法添加到该类中。该方法定义如下: ```java ClassMethod XMLNew(doc As %XML.Document, node As %Integer, contOref As %RegisteredObject = "") As GXML.PersonWithXMLNew { Set id="" Set tmpnode=doc.GetNode(node) Do tmpnode.MoveToFirstChild() Do { //将数据节点与NAMEOFEXPORTID参数提供的字符串进行比较 //指示此对象的ID的XMLNAME If tmpnode.NodeData=..#NAMEOFEXPORTID { //从该节点获取文本;这与数据库中的id相对应 Do tmpnode.GetText(.id)} } While tmpnode.MoveToNextSibling() //如果给定节点中没有id,则创建一个新对象 If id="" { Write !, "正在创建新对象..." Quit ..%New()} //打开给定对象 Set result=..%OpenId(id) //如果id与现有对象不对应,则创建一个新对象 If result=$$$NULLOREF { Write !, "正在创建新对象..." Quit ..%New()} Write !, "正在更新现有对象..." Quit result } ``` `%XML.Reader`读取`XML`文档并将节点关联到`GXML.PersonWithXMLNew`时调用此方法。此方法查看此类中的`NAMEOFEXPORTID`参数的值,即`IRISID`。然后,它使用元素`IRISID`检查文档中的节点并获取其值。 如果此`ID`对应于此类的现有对象,则该方法将打开该实例。否则,该方法将打开此类的新实例。在这两种情况下,实例都会接收`XML`文档中指定的属性。 最后,以下实用程序类包含一个方法,该方法打开`XML`文件并在新窗口中调用`%XML.Reader`: ```java /// w ##class(PHA.TEST.Xml).ReadFile() ClassMethod ReadFile(filename As %String = "e:\temp\xmlnewtest.xml") { Set reader=##class(%XML.Reader).%New() Set sc=reader.OpenFile(filename) If $$$ISERR(sc) {Do $system.OBJ.DisplayError(sc) Quit } Do reader.Correlate("Person","GXML.PersonWithXMLNew") //loop through elements in file While reader.Next(.person,.sc) { Write !,person.Name,! Set sc=person.%Save() If $$$ISERR(sc) {Do $system.OBJ.DisplayError(sc) Quit } } Quit "" } ``` 运行上述方法时,文件中的每个``元素都会发生以下情况之一: - 打开现有对象,使用文件中的详细信息进行更新,然后保存。 - 或者创建一个新对象,其中包含文件中的详细信息。 ```java DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在创建新对象... Quine,Maria K. DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在创建新对象... Quine,Maria K. DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在创建新对象... Quine,Maria K. DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在更新现有对象... Quine,Maria K. DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在更新现有对象... Quine,Maria K. DHC-APP>w ##class(PHA.TEST.Xml).ReadFile() 正在更新现有对象... Quine,Maria K. ``` ## 示例2:在自定义XML适配器中修改XMLNew() 在第二个示例中,我们创建一个自定义XML适配器来执行与第一个示例相同的操作。适配器类如下所示: ```java Class GXML.AdaptorWithXMLNew Extends %XML.Adaptor { /// 确保这与该类中属性的XMLNAME相同 它的类型为%XML.Id Parameter NAMEOFEXPORTID As %String = "IRISID"; Property IdForExport As %XML.Id(XMLNAME = "IRISID", XMLPROJECTION = "ELEMENT") [ Private, Transient ]; ClassMethod XMLNew(document As %XML.Document, node As %Integer, containerOref As %RegisteredObject = "") As %RegisteredObject [ CodeMode = objectgenerator, GenerateAfter = %XMLGenerate, ServerOnly = 1 ] { If %compiledclass.Name'="GXML.AdaptorWithXMLNew" { Do %code.WriteLine(" Set id=""""") Do %code.WriteLine(" Set tmpnode=document.GetNode(node)") Do %code.WriteLine(" Do tmpnode.MoveToFirstChild()") Do %code.WriteLine(" Do {") Do %code.WriteLine(" If tmpnode.NodeData=..#NAMEOFEXPORTID ") Do %code.WriteLine(" {Do tmpnode.GetText(.id)}") Do %code.WriteLine(" } While tmpnode.MoveToNextSibling() ") Do %code.WriteLine(" If id="""" {") Do %code.WriteLine(" Write !,""Creating new object...""") Do %code.WriteLine(" Quit ##class("_%class.Name_").%New()}") Do %code.WriteLine(" set result=##class("_%class.Name_").%OpenId(id)") Do %code.WriteLine(" If result=$$$NULLOREF {") Do %code.WriteLine(" Write !,""Creating new object...""") Do %code.WriteLine(" Quit ##class("_%class.Name_").%New() }") Do %code.WriteLine(" Write !,""Updating existing object ...""") Do %code.WriteLine(" Quit result") } QUIT $$$OK } } ``` `IdForExport`属性和`NAMEOFEXPORTID`参数建立了一个约定,用于在导出子类的对象时如何将InterSystems IRIS内部`ID`投影到元素。其目的是,如果在子类中重新定义`IdForExport`,则相应地重新定义`NAMEOFEXPORTID`。 在这个类中,`XMLNew()`方法是一个方法生成器。编译该类(或任何子类)时,InterSystems IRIS会将此处显示的代码写入此方法的主体中。 以下类扩展了我们的自定义适配器: ```java Class GXML.PersonWithXMLNew2 Extends (%Persistent, %Populate, GXML.AdaptorWithXMLNew) { Parameter XMLNAME = "Person"; Property Name As %Name; Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h"); Property Address As GXML.Address; Property Doctors As list Of GXML.Doctor; } ``` 当运行前面显示的示例`ReadFile`方法时,对于文件中的每个 ``元素,该方法要么创建并保存一条新记录,要么打开并更新现有记录。
文章
姚 鑫 · 六月 16, 2021

第九章 将XML导入到对象中

# 第九章 将XML导入到对象中 本章介绍如何使用%XML.Reader将XML文档导入到 IRIS对象中。 **注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码, IRIS将使用前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。** 还可以使用`%XML.Reader`读取任意XML文档并返回DOM(文档对象模型)。 # 创建XML读取器概述 IRIS提供了一些工具,用于读取XML文档并创建与该文档的元素相对应的启用XML的 IRIS对象的一个或多个实例。基本要求如下: - 该对象的类定义必须扩展`%XML.Adaptor`。除了少数例外,该对象引用的类还必须扩展`%XML.Adaptor`。 提示:如果相应的XML模式可用,可以使用它来生成类(以及任何支持的类)。 - 要导入XML文档,创建`%XML.Reader`的实例,然后调用该实例的方法。这些方法指定XML源文档,将XML元素与启用XML的类相关联,并将源中的元素读取到对象中。 `%XML.Reader`使用类中的`%XML.Adaptor`提供的方法执行以下操作: - 它使用InterSystems IRIS SAX接口解析和验证传入的XML文档。验证可以包括DTD或XML架构验证。 - 它确定是否有任何启用了XML的对象与XML文档中包含的元素相关,并在读取文档时创建这些对象的内存中实例。 **请注意,`%XML.Reader`创建的对象实例不存储在数据库中;它们是内存中的对象。如果要将对象存储在数据库中,则必须调用%Save()方法(对于持久对象),或者将相关属性值复制到持久对象并保存它。应用程序还必须决定何时插入新数据和何时更新现有数据;`%XML.Reader`无法进行此区分。** 下面的终端会话显示了一个简单的示例。在这里,我们将XML文件读入一个新对象,检查该对象,然后保存该对象: ```java /// w ##class(PHA.TEST.Xml).ReadXml() ClassMethod ReadXml() { Set reader = ##class(%XML.Reader).%New() Set file="E:\temp\samplePerson.xml" Set status = reader.OpenFile(file) if $$$ISERR(status) { do $System.Status.DisplayError(status) quit } Write status,! Do reader.Correlate("Person","Sample.Person") Do reader.Next(.object,.status) if $$$ISERR(status) { do $System.Status.DisplayError(status) quit } Write object.Name,! Do object.%Save() q "" } ``` 此示例使用以下示例XML文件: ```java Worthington,Jeff R. 1976-11-03 Elm City 27820 Best,Nora A. Weaver,Dennis T. ``` # 创建导入方法 ## 总体方法结构 方法应按以下顺序执行以下部分或全部操作: 1. 创建`%XML.Reader`的实例。 2. 也可以指定此实例的`Format`属性,以指定要导入的文件的格式。 默认情况下,InterSystems IRIS假定XML文件为文字格式。如果文件是SOAP编码格式,则必须指明这一点,以便可以正确读取该文件。 3. 可以选择设置此实例的其他属性。 4. 请使用`%XML.Reader`的以下方法之一 - `OpenFile()` -打开文件。 - `OpenStream()`-打开一个流。 - `OpenString()` -打开一个字符串。 - `OpenURL()` -打开一个URL。 在每种情况下,可以选择性地为该方法指定第二个参数,以覆盖`Format`属性的值。 5. 将这个文件中的一个或多个XML元素名与具有相应结构的支持InterSystems IRIS XML的类关联起来。 有两种方法可以做到这一点: - 使用`Correlate()`方法,它有以下签名: ``` method Correlate(element As %String, class As %String, namespace As %String) ``` 其中`element`是XML元素名,class是InterSystems IRIS类名(带包),`namespace`是可选的名称空间`URI`。 如果使用`namespace`参数,则匹配仅限于指定命名空间中的指定元素名。 如果将命名空间参数指定为"",则与`Next()`方法中给出的默认命名空间相匹配。 如果不使用`namespace`参数,则只使用元素名进行匹配。 提示:可以反复调用`Correlate()`方法来关联多个元素。 - 使用`CorrelateRoot()`方法,它有以下签名: ``` method CorrelateRoot(class As %String) ``` 其中class是InterSystems IRIS类名(带包)。此方法指定XML文档的根元素与指定的类相关。 6. 按如下方式实例化类实例: 如果使用`Correlate()`,则遍历文件中的相关元素,一次循环一个元素。在循环中,使用Next()方法,该方法具有以下签名: ``` method Next(ByRef oref As %ObjectHandle, ByRef sc As %Status, namespace As %String = "") as %Integer ``` 其中`OREF`是该方法创建的对象,`sc`是状态,`Namespace`是文件的默认名称空间。 - 如果使用`CorrelateRoot()`,请调用`next()`方法一次,这会导致实例化相关类。 `Next()`方法在到达文件末尾时返回0。如果在此之后再次调用`next()`,则将从文件顶部开始再次循环遍历文件中的对象。(指定的关联仍然有效。) ## 错误检查 **上一节提到的大多数方法都返回状态。应该在每个步骤之后检查状态,并在适当的情况下退出。** ## 基本导入示例 名为`test.xml`的以下XML文件: ```xml 姚 鑫 ``` 我们首先定义一个启用XML的类`MyApp.Person`,它是`Person`的对象表示: ```java Class MyApp.Person Extends (%Persistent, %XML.Adaptor) { Parameter XMLNAME = "Person"; Property Name As %String; Storage Default { %%CLASSNAME Name ^MyApp.PersonD PersonDefaultData ^MyApp.PersonD ^MyApp.PersonI ^MyApp.PersonS %Library.CacheStorage } } ``` 要将此文件导入到`MyAppPerson`类的实例中,我们可以编写以下方法: ```java /// w ##class(PHA.TEST.Xml).ImportXml() ClassMethod ImportXml() { // 创建%XML.Reader的实例 Set reader = ##class(%XML.Reader).%New() // 开始处理文件 Set status = reader.OpenFile("E:\temp\testPerson.xml") If $$$ISERR(status) {do $System.Status.DisplayError(status)} // 将类名与XML元素名相关联 Do reader.Correlate("Person","MyApp.Person") // 从XML文件读取对象 While (reader.Next(.object,.status)) { Write object.Name,! } // 如果在处理过程中发现错误,则将其显示 If $$$ISERR(status) {do $System.Status.DisplayError(status)} q "" } ``` ```java DHC-APP>w ##class(PHA.TEST.Xml).ImportXml() 姚 鑫 ``` 此方法执行几个任务: - 它使用InterSystems IRIS `SAX`接口解析输入文件。这包括根据文档的DTD或架构(如果指定)验证文档。 - `Correlate()`方法将类`MyApp`关联起来。 `MyPerson`与XML元素``; ``中的每个子元素都成为`MyPerson`的一个属性。 - 它从输入文件中读取每个``元素,直到没有剩余元素。 - 最后,如果循环因错误而终止,则该错误将显示在当前输出设备上。 如上所述,此示例不将对象存储到数据库。因为`MyPerson`是持久对象,所以可以通过在`While`循环中添加以下行来完成此操作: ```java /// w ##class(PHA.TEST.Xml).ImportXml() ClassMethod ImportXml() { // 创建%XML.Reader的实例 Set reader = ##class(%XML.Reader).%New() // 开始处理文件 Set status = reader.OpenFile("E:\temp\testPerson.xml") If $$$ISERR(status) {do $System.Status.DisplayError(status)} // 将类名与XML元素名相关联 Do reader.Correlate("Person","MyApp.Person") // 从XML文件读取对象 While (reader.Next(.object,.status)) { Write object.Name,! Set savestatus = object.%Save() If $$$ISERR(savestatus) {do $System.Status.DisplayError(savestatus)} } // 如果在处理过程中发现错误,则将其显示 If $$$ISERR(status) {do $System.Status.DisplayError(status)} q "" } ``` ![image](6AAE53278D13494E959BC90CC739F33C) ## 通过HTTPS URL访问文档 对于`OpenURL()`方法,如果文档位于需要`SSL/TLS`的`URL`,请执行以下操作: 1. 使用管理门户创建包含所需连接详细信息的`SSL/TLS`配置。这是一次性的步骤。 2. 使用`%XML.Reader`时,请设置读取器实例的`SSLConfiguration`属性。对于该值,请指定在上一步中创建的SSL/TLS配置的名称。 或者,当使用`%XML.Reader`,还可以执行以下操作: 1. 创建`%Net.HttpRequest`实例。 2. 将该实例的`SSLConfiguration`属性设置为等于管理门户中创建的`SSL/TLS`配置的配置名称。 3. 使用`%Net.HttpRequest`的实例作为`OpenURL()`的第三个参数。 例如: ![image](31D8EC126E9F4C3D92C558742C3FC0B7) ```java Class YX.Config Extends (%Persistent, %XML.Adaptor) { Parameter XMLNAME = "update"; Property version As %String; Property name As %String; Property url As %String; } ``` ```java /// 请求http的xml,映射到本地类 /// w ##class(PHA.TEST.Xml).ReadXmlHttp("http://192.168.10.3/dthealth/web/csp/version.xml") ClassMethod ReadXmlHttp(url) { set reader = ##class(%XML.Reader).%New() set request = ##class(%Net.HttpRequest).%New() set request.SSLConfiguration="yx" set status = reader.OpenURL(url,,request) If $$$ISERR(status) {do $System.Status.DisplayError(status)} // 将类名与XML元素名相关联 Do reader.Correlate("update","YX.Config") While (reader.Next(.object,.status)) { Write object.version,! Write object.name,! Write object.url,! } q "" } ``` ```java DHC-APP>w ##class(PHA.TEST.Xml).ReadXmlHttp("http://192.168.10.3/dthealth/web/csp/version.xml") 27 Herb http://192.168.31.124/dthealth/web/csp/Herb.apk ``` ### 在服务器需要身份验证时访问文档 **如果服务器需要身份验证,请创建`%Net.HttpRequest`的实例,并设置该实例的用户名和密码属性。还可以如上所述使用SSL(因此还要设置`SSLConfiguration`属性)。然后使用`%Net.HttpRequest`的实例作为`OpenURL()`的第三个参数,如上例所示。**
公告
Claire Zheng · 六月 16, 2021

6月19日直播报名 | 国内外互联互通标准解读与实践

为了解国内外最新的互联互通标准,共同助推我国卫生信息互联互通标准化成熟度测评工作,指导各地医院信息平台的建设,《中国卫生信息管理杂志》社决定召开国内外互联互通标准解读与实践线上交流会。会议由《中国卫生信息管理杂志》社主办,InterSystems中国协办,欢迎报名参会!