搜索​​​​

清除过滤器
文章
姚 鑫 · 六月 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中国协办,欢迎报名参会!
公告
jieliang liu · 六月 15, 2021

InterSystems IRIS、IRIS for Health和HealthShare Health Connect 2021.1现已正式发布。

InterSystems非常高兴地宣布,InterSystems IRIS数据平台、InterSystems IRIS for Health和HealthShare Health Connect的2021.1版本现已向我们的客户和合作伙伴全面开放。 这个版本的为开发者提供了更大的自由度,使他们可以用自己选择的编程语言在服务器端和客户端建立快速和强大的应用程序。这个版本还使用户能够通过新的和更快的分析能力更有效地消费大量的信息。 我们期望许多客户和合作伙伴将他们的Caché和Ensemble部署升级到InterSystems的IRIS版本,并尽一切努力使之成为一个平稳和值得的过渡。大多数应用程序在IRIS上运行后会立即看到性能上的好处,甚至在他们探索IRIS带来的许多强大功能之前。 我们诚挚地邀请您参加我们的网络研讨会,介绍新版本的亮点,时间是美国东部时间6月17日上午11点。网络研讨会将被记录下来,并在会后进行 重播。 Release Highlights 在InterSystems IRIS 2021.1,客户可以部署 InterSystems IRIS Adaptive Analytics,Adaptive Analytics是一个附加产品,它扩展了InterSystems IRIS,为商业用户提供了卓越的易用性和自助分析能力,使他们能够对大量数据进行可视化、分析和查询,以获得他们所需的信息,从而做出及时和准确的商业决策,而无需是数据设计或数据管理方面的专家。Adaptive Analytics通过在后台自主构建和维护临时数据结构,透明地加速了针对InterSystems IRIS运行的分析查询工作负载。 该版本中的其他新亮点功能包括。 改进了我们的外部语言服务器的可管理性,现在也包括R和Python。这种网关技术使您能够以您选择的语言稳健和可扩展地利用服务器端代码。 InterSystems Kubernetes Operator(IKO)为您的环境提供声明式配置和自动化,现在还支持部署InterSystems System Alerting & Monitoring(SAM)。 InterSystems API Manager v2.3,包括改进的用户体验、Kafka支持和混合模式。 IntegratedML的主流可用性,使SQL开发人员能够直接在一个纯粹的基于SQL的环境中构建和部署机器学习模型。 支持分片表上的流字段,使您在InterSystems IRIS水平可扩展架构上获得完全的SQL模式灵活性。 一个iris-lockeddown容器镜像,实现了许多安全最佳实践,如禁用管理门户的网络访问和适当的操作系统级权限。 支持用于Oauth 2.0的代码交换的证明密钥(PKCE)。 InterSystems IRIS for Health 2021.1包括InterSystems IRIS的所有改进功能。此外,该版本通过用于解析和评估FHIRPath表达式的API,进一步扩展了该平台对FHIR®标准的全面支持。这是对2020.1以来发布的重要的FHIR相关功能的补充,包括对FHIR Profiles、FHIR R4 Transforms和FHIR客户端API的支持。 该版本还包括HealthShare Health Connect,这是我们基于IRIS for Health的集成引擎,提供大批量的交易支持、流程管理和监控,以支持关键任务应用。有关其功能集与InterSystems IRIS for Health的比较的详细概述,请参见这里。 关于所有这些功能的更多细节可以在产品文档中找到,该文档最近通过方便的目录侧边栏变得更加容易浏览。 InterSystems IRIS 2021.1 文档和发布说明 InterSystems IRIS for Health 2021.1 文档和发布说明 HealthShare Health Connect 2021.1 文档和发布说明 如果您从早期版本升级并使用TLS 1.3,请参见这些升级注意事项。 如何获得软件 InterSystems IRIS 2021.1是一个扩展维护(EM)版本,并附带有适用于所有支持平台的经典安装包,以及OCI(Open Container Initiative)又称Docker格式的容器镜像。 每个产品的完整安装包都可以从WRC的产品下载网站获得。使用 "自定义 "安装选项使用户能够选择他们需要的选项,如InterSystems Studio和IntegratedML,以合理地缩小其安装规模。 InterSystems IRIS和IRIS for Health的企业版容器映像以及所有相应的组件可通过InterSystems容器注册中心使用以下命令获得: docker pull containers.intersystems.com/intersystems/iris:2021.1.0.215.0 docker pull containers.intersystems.com/intersystems/iris-ml:2021.1.0.215.0 docker pull containers.intersystems.com/intersystems/irishealth:2021.1.0.215.0 docker pull containers.intersystems.com/intersystems/irishealth-ml:2021.1.0.215.0 有关可用图像的完整列表,请参考ICR文件。 社区版的容器图像也可以使用以下命令从Docker商店中提取。 docker pull store/intersystems/iris-community:2021.1.0.215.0 docker pull store/intersystems/iris-ml-community:2021.1.0.215.0 docker pull store/intersystems/irishealth-community:2021.1.0.215.0 docker pull store/intersystems/irishealth-ml-community:2021.1.0.215.0 另外,所有容器镜像的tarball版本可以通过WRC的产品下载网站获得。 InterSystems IRIS Studio 2021.1是一个独立的IDE,用于Microsoft Windows,可以通过WRC的产品下载网站下载。它适用于InterSystems IRIS和IRIS for Health 2021.1及以下版本。InterSystems还支持VSCode ObjectScript插件,用于用Visual Studio Code为InterSystems IRIS开发应用程序,该插件可用于Microsoft Windows、Linux和MacOS。 其他独立的InterSystems IRIS 2021.1组件,如ODBC驱动程序和Web网关,可从同一页面获得。 分享您的经验 我们每年只能宣布一个EM版本,所以我们很高兴看到这个版本现在达到了GA的里程碑,并渴望听到你对新软件的体验。请不要犹豫,通过您的客户团队或在开发人员社区上与您联系,对该技术或您使用该技术解决的使用案例提出任何意见。 对于选定的新功能和产品,我们已经建立了早期访问计划,允许我们的用户在软件发布之前进行评估。通过这些有针对性的举措,我们可以向目标受众学习,并确保新产品在发布时能够满足他们的需求。如果您有兴趣参与其中任何一项,请通过您的客户团队或观看开发人员社区进行联系。
文章
姚 鑫 · 六月 15, 2021

第七章 控制命名空间分配的外观

# 第七章 控制命名空间分配的外观 # 控制命名空间分配的外观 除了控制命名空间分配外,还可以控制命名空间分配在XML输出中的显示方式。具体地说,可以控制以下内容: ## 显式名称空间分配与隐式名称空间分配 将元素和属性分配给命名空间时,XML中有两种等效的表示形式,由编写器实例的`SuppressXmlns`属性控制。 为一个名为`Person`的对象生成XML输出,该对象被分配给名称空间`“http://www.person.org”`(通过前面讨论的`namespace`类参数)。 使用缺省输出(`SuppressXmlns`等于0)的示例如下: ```java Uberoth,Amanda Q. 1952-01-13 ``` 另一种可能的形式完全相同,如下所示。 这是使用`SuppressXmlns`等于1生成的,它确保显式分配给名称空间的每个元素都显示为该名称空间的前缀。 ```java Uberoth,Amanda Q. 1952-01-13 ``` 请注意,此属性仅影响命名空间分配的显示方式;它不控制如何分配任何命名空间。如果不使用命名空间,则此参数无效。 ## 为命名空间指定自定义前缀 当为对象生成XML输出时,系统会根据需要生成命名空间前缀。第一个名称空间前缀是`s01`,下一个是`s02`,依此类推。可以指定不同的前缀。为此,请在启用XML的对象本身的类定义中设置`XMLPREFIX`参数。此参数有两个效果: - 它确保在XML输出中声明指定的前缀。也就是说,即使没有必要这样做,它也会被声明。 - 它使用该前缀,而不是在其他情况下会看到的自动生成的前缀。 # 控制空字符串(`""`)的导出方式 为对象启用XML时,需要指定将空值和空字符串投影到XML的方式 其中一个选项是在支持xml的类中将`XMLIGNORENULL`设置为`“RUNTIME”`(不区分大小写)。 在这种情况下,当使用%XML.Write的`RuntimeIgnoreNull`属性的值来确定如何处理任何等于`""`的属性,如下所示: - **如果编写器的`RuntimeIgnoreNull`属性为0(默认值),则`XMLNIL`参数控制如何导出该属性。`XMLNIL`是一个类参数和一个属性参数;属性参数优先。** - 如果`XMLNIL`为0(默认值),则不投影特性。也就是说,它不包含在XML文档中。 - 如果`XMLNIL`为1,并且该属性用作元素,则该属性将按如下方式导出: ``` ``` - 如果`XMLNIL`为1并且特性用作属性,则不会输出特性。 - 如果编写器的`RuntimeIgnoreNull`属性为1,则该属性将导出为空元素或空属性(其导出方式与值`$char(0)`相同,后者始终导出为空元素或空导出)。 除非`XMLIGNORENULL`在启用xml的类中是`“RUNTIME”`,否则编写器的`RuntimeIgnoreNull`属性是无效的。 ## 示例:`RuntimeIgnoreNull`为0(默认值) ```java Class EmptyStrings.Export Extends (%Persistent, %XML.Adaptor) { Parameter XMLNAME="Test"; Parameter XMLIGNORENULL = "RUNTIME"; ///把这个作为一个元素 ///XMLNIL is 0, the default Property Property1 As %String; ///把这个作为一个元素 ///XMLNIL is 0, the default Property Property2 As %String(XMLPROJECTION = "ATTRIBUTE"); ///将其作为XMLNIL=1的元素 Property Property3 As %String(XMLNIL = 1); ///将其作为XMLNIL=1的属性进行项目 Property Property4 As %String(XMLNIL=1,XMLPROJECTION="ATTRIBUTE"); } ``` 如果创建了这个类的一个新实例(并且没有设置任何属性的值),然后使用 `%XML.Writer`输出,如下所示: ```java ``` ## 例如:`RuntimeIgnoreNull`为1 ```java ``` **在本例中,因为`RuntimeIgnoreNull`为1,所以没有使用`XMLNIL`参数。 相反,`""`被导出为空属性或空元素。** # 导出类型信息 默认情况下,XML编写器不写入类型信息。有两个选项可用于在输出中包括类型信息: - 编写器的`OutputTypeAttribute`属性。如果此属性为1,则编写器包括其写入的对象内所有元素的XML类型信息(但不包括对象本身)。例如: ```java Petersburg,Greta U. 1949-05-15 ``` 请注意,相应的命名空间将添加到XML文档的根。 - `Object()`和`RootObject()`方法的`className`参数。此参数用于指定对象的预期`ObjectScript`类型(类名)。 如果参数与实际类型相同,则编写器不包括对象的类型信息。 如果参数与实际类型不同,编写器将包括对象的实际XML类型(默认为类名)。例如,假设`Test2.PersonWithAddress`实例编写输出,并将`className`参数指定为`MyPackage.MyClass`。因为`MyPackage.MyClass`与实际的类名不同,所以编写器生成以下输出: ```java Avery,Robert H. Ukiah 82281 ``` # 生成SOAP编码的XML 对于`%XML.Writer`,`Format`属性控制输出的整体格式。这是以下选项之一: - `“literal”`,即默认值,在本书的大多数例子中都使用了它。 - `“encoded”`,按照SOAP 1.1标准中的描述进行编码。 - `“encoded12”`,按照SOAP 1.2标准中的描述进行编码。 ## 创建内联引用 在编码格式中,任何对象值属性都被作为引用包含,被引用的对象被导出为单独的元素。 要将这些属性内联导出,而不是作为单独的元素,请将`ReferencesInline`属性设置为1。 如果格式是`“literal”`,`ReferencesInline`属性没有效果。 # 导出后控制unswizling 当导出一个支持xml的持久对象时,系统会像往常一样自动将所有需要的信息混合到内存中;该信息包括对象值属性。导出对象后,InterSystems IRIS将消除任何对象列表,但(默认情况下)不会消除单个对象引用。 对于大对象,这可能导致``错误。 在这种情况下,要使任何单个对象引用不被混合,请在支持xml的类中设置`XMLUNSWIZZLE`参数,如下所示: ```java Parameter XMLUNSWIZZLE = 1; ``` 该参数默认值为0。 # 控制元素的关闭 只包含属性的元素可以用以下任一方式表示: ```java ``` `Object()`方法始终使用第一个语法导出元素。如果需要使用此处显示的第二种语法关闭元素,请手动编写对象,如本章前面的“手动构造元素”中所述。 咨询一下,我也是初学,有没有类似于oracle的exp远程备份数据库的方法?
文章
Michael Lei · 六月 15, 2021

InterSystems 最佳实践之--LVM PE 条带化使超融合存储吞吐量最大化

本帖概述了通过为 InterSystems 数据平台(InterSystems IRIS、Caché 和 Ensemble)上的数据库磁盘创建 LVM 物理盘区 (PE) 条带来实现低延迟存储 IO 的最佳实践配置,并提供了有用链接。 一致的低延迟存储是获得最佳数据库应用程序性能的关键。 例如,对于在 Linux 上运行的应用程序,经常在数据库磁盘中使用逻辑卷管理器 (LVM) ,因为它能够扩展卷和文件系统,或者为在线备份创建快照。 对于数据库应用程序,在使用 LVM PE 条带化逻辑卷的情况下,并行写入还可提高数据 I/O 的效率,从而有助于提高大规模连续读取和写入的性能。 ---- 本帖重点介绍在 HCI 中使用 LVM PE 条带,也受到了社区中发布的[软件定义的数据中心 (SDDC) 和超融合基础架构 (HCI) – InterSystems 客户的重要注意事项](https://community.intersystems.com/post/software-defined-data-centers-sddc-and-hyper-converged-infrastructure-hci-%E2%80%93-important "SDDC whitepaper")白皮书的启发。 该白皮书推荐“对 Linux 虚拟机使用 LVM PE 条带化,从而将 IO 分布在多个磁盘组”以及“对于 Linux 虚拟机上的所有数据库和写入映像日志 (WIJ) 文件使用异步 IO 及 rtkaio 库”。 本帖提供了这些要求和示例的一些上下文信息。 ---- __注:__ > 目前有多个超融合、融合和软件定义的供应商平台,我在本帖中不会提供每个平台的详细说明,而是以__在 VMware ESXi 和 vSAN 上运行的 Red Hat Enterprise Linux (RHEL) 7.4 上的 InterSystems IRIS 或 Caché __的配置作为示例进行说明。 不过,其他解决方案的基本过程是相似的,特别是在 InterSystems IRIS 或 Caché 和操作系统层面。 如果您不确定如何将这些说明转换到其他平台,请联系各供应商的支持人员,了解他们的最佳实践。 InterSystems 技术专家还可以直接向客户和供应商或通过社区提供建议。 还需要注意的是,本帖中关于 LVM PE 条带化的指南既适用于 HCI,也适用于“传统”存储。 ---- ## 是否必须使用 LVM 条带化? 对于磁盘阵列等传统存储,简短的答案是“否”。 对数据库磁盘运行 LVM 条带化卷并不是必需的,尤其是使用现代全闪存阵列的情况下;如果性能尚可,并且您没有 LVM 需求,则无需改动。 但是,如上文所述,建议在 Nutanix 和 VMware VSAN 等超聚合和存储解决方案上的数据库磁盘中使用 LVM 条带,以便在 IO 操作中可以使用更多主机节点和磁盘组。 ## 为什么对数据平台使用 LVM 条带? 特别建议 HCI 上的数据库磁盘使用 LVM 条带,以降低某些架构功能的性能开销,例如减轻写入守护进程 (WD) 对数据库写入和日志写入的影响。 使用 LVM 条带将数据库突发写入分散到更多磁盘设备和多个磁盘组。  此外,本帖还将说明如何增加大规模 IO 写入映像日志 (WIJ) 的并行性,从而减少对其他 IO 的延迟影响。 > 注意:在本帖中,当我提到“磁盘”时,我指的是 NVMe、Optane、SATA 或 SAS SSD,或者任何其他闪存设备。 ## vSAN 存储架构概述 HCI 存储(例如在 vSAN 上运行 ESXi 时)使用两个磁盘层:一个缓存层和一个容量层。 对于全闪存架构__(必须使用全闪存,不要使用旋转磁盘!)__,所有写入操作都在缓存层进行,随后数据最终会转移到容量层。 读取来自容量层(也可能来自缓存层上的缓存)。 HCI 集群中的每个主机都可以有一个或多个磁盘组。 在使用磁盘组的情况下(例如使用 VSAN 时),每个磁盘组都由一个缓存磁盘和多个容量磁盘组成。 例如,缓存磁盘是单个 NVMe 磁盘,容量磁盘是三个或更多写密集型 SAS SSD 磁盘。 有关 HCI(包括 vSAN 磁盘组)的更多详细信息,请参见社区上的帖子“[超融合基础架构 (HCI)](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-%E2%80%93-part-8-hyper-converged-infrastructure-capacity "HCI")”或联系您的 HCI 供应商。 ## LVM 条带化逻辑卷概述 [Red Hat 支持](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/logical_volume_manager_administration/lv_overview "Red Hat support")网站上提供了很好的 Linux LVM 概述,[其他地方,例如这里的面向系统管理员的教程也非常好](https://sysadmincasts.com/episodes/27-lvm-linear-vs-striped-logical-volumes "Striped")。 ## 数据平台存储 IO 了解 InterSystems 数据平台生成的 IO 类型很重要。 [社区中提供了存储 IO 模式](https://community.intersystems.com/post/data-platforms-and-performance-part-6-cach%C3%A9-storage-io-profile "Storage IO")的概述。 ---- # 创建 LVM PE 条带的过程 ## 先决条件和步骤 在我们深入讨论该过程之前,您还应该记住,其他变数也可能影响存储性能。 仅创建 LVM 条带并不能保证实现最佳性能,还必须考虑存储类型,以及整个 IO 路径,包括 IO 队列和队列深度。 本示例适用于 VMware,您还应该阅读 [InterSystems IRIS VMware 最佳实践指南](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-%E2%80%93-part-9-intersystems-iris-vmware-best-practice "VMware best practice guide"),并应用其中的建议。 尤其是存储方面的注意事项,例如跨 PVSCSI 控制器分离存储 IO 类型。 ### 概述 以下示例展示了在 VMware ESXi 和 VSAN 6.7 上运行的 Red Hat Enterprise Linux (RHEL) 7.4 上使用 InterSystems IRIS 或 Caché 的最佳实践。 下文介绍以下步骤: 1. ESXi 配置 2. RHEL 配置 3. Caché/InterSystems IRIS 配置 ---- ## 1. ESXi 配置 ### a) 创建 VMDK 磁盘 必须按照 [InterSystems IRIS VMware 最佳实践指南](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-%E2%80%93-part-9-intersystems-iris-vmware-best-practice "VMware best practice guide")创建磁盘;数据库、日志和 WIJ 在不同的 PVSCI 设备上。 创建的 VMDK 数量取决于您的规模调整要求。 在本示例中,数据库文件系统将由四个 255 GB VMDK 磁盘组成,这些磁盘将一起条带化,为数据库文件系统创建一个 900GB 逻辑磁盘。 #### 步骤: 1. 在添加 VMDK 前关闭虚拟机。 2. 在 vCenter 控制台中创建多个磁盘 (VMDK),每个磁盘为 255GB,单个 LVM 条带中的所有磁盘都必须与同一个 PVSCSI 控制器关联。 3. 启动虚拟机。 在启动过程中,将在操作系统中创建新磁盘,例如 `/dev/sdi` 等。 > __为什么创建多个 255 GB VMDK?__在 vSAN 中,存储组件以 256 GB 区块为单位创建,我们将 VMDK 大小保持在恰好低于 256 GB,是为了强制使组件位于不同的磁盘组上。 从而实施另一个层面的条带化(在我的测试中是这样,但我不保证 vSAN 实际也是如此)。 注意:在创建过程中,vSAN 将磁盘组件分布到所有主机和磁盘组,以确保可用性。 例如,在允许的故障数 (FTT) 设置为 2 的情况下,每个磁盘组件有三个副本,加上两个小的见证组件,全部都在不同的主机上。 如果磁盘组、主机或网络发生故障,应用程序将使用其余磁盘组件继续运行,而不会丢失数据。 我们对这个过程可能多虑了! 在 vSAN 等 HCI 解决方案中,无法控制组成 VMDK 的组件在某个时间点位于哪个物理磁盘上。 事实上,由于维护、重新同步或重建的原因,随着时间的推移,VMDK 可能会移动到不同的磁盘组或主机上。 这是正常的。 ---- ## 2. RHEL 配置 ### a) 确认对于每个磁盘设备,RHEL IO 调度器都为 NOOP。 最佳实践是使用 ESXi 内核的调度器。 有关设置调度器的更多信息,请参见 [Red Hat 知识库文章](https://access.redhat.com/solutions/109223 "Setting noop")。 我们建议在启动时为所有设备设置该选项。 要验证是否已正确设置调度器,可以显示磁盘设备(例如,在本例中为 `/dev/sdi`)的当前设置,如下所示: [root@db1 ~]# cat /sys/block/sdi/queue/scheduler [noop] deadline cfq 您可以看到 noop 已启用,因为它放在方括号中突出显示。 ### b) 创建条带化的 LVM 和 XFS 文件系统 现在,我们准备在 RHEL 中创建 LVM 条带和数据库文件系统。 以下是所涉及步骤的示例,请注意,对于您的环境,需要替换虚构的名称 vgmydb、lvmydb01 和路径 /mydb/db。 #### 步骤 **1.** 使用 `vgcreate` 命令创建带有新磁盘设备的卷组。 vgcreate -s 4M 例如,如果创建磁盘 /dev/sdh、/dev/sdi、/dev/sdj 和 /dev/sdk: vgcreate -s 4M vgmydb /dev/sd[h-k] **2.** 使用 `lvcreate` 命令创建条带化逻辑卷。 建议至少四个磁盘。 从 4MB 条带开始,但是对于非常大的逻辑卷,系统可能会提示您选择更大的大小,如 16M。 lvcreate -n -L -i -I 4MB 例如,要创建带有 4 个条带的 900GB 磁盘,且条带大小为 4 MB: lvcreate -n lvmydb01 -L 900G -i 4 -I 4M vgmydb **3.** 使用 `mkfs` 命令创建数据库文件系统。 mkfs.xfs -K 例如: mkfs.xfs -K /dev/vgmydb/lvmydb01 **4.** 创建文件系统挂载点,例如: mkdir /mydb/db **5.** 编辑 `/etc/fstab` 以添加以下挂载条目并挂载文件系统。 例如: /dev/mapper/vgmydb-lvmydb01 /mydb/db xfs defaults 0 0 **6.** 挂载新的文件系统。 mount /mydb/db ---- ## 3. Caché/InterSystems IRIS 配置 本节我们将配置: - 异步和直接 IO,以实现数据库和 WIJ 的最佳写入性能。 这也为数据库读取操作启用了直接 IO。 > 注意:由于直接 IO 会绕过文件系统缓存,因此在配置直接 IO 后,操作系统文件复制操作(包括 Caché 在线备份)将非常慢。 为提高 **RHEL** 上的 WIJ 的性能并实现最低延迟(SuSE 9 及更高版本不支持),并减少对其他 IO 的影响,我们还将配置: - 将 `rtkaio` 库用于使用 Caché 的 RHEL 系统。 **注意:IRIS 不需要这个库。** > 注:对于 Linux 上版本号以 2017.1.0. 开头的 Caché、Ensemble 和 HealthShare 发行版 (仅当备份或异步镜像成员配置为使用 rtkaio 时),必须应用 [ RJF264,可通过 InterSystems 全球响应中心 (WRC) 的特别分发获取](https://www.intersystems.com/support-learning/support/product-news-alerts/support-alert/alert-linux-defects-can-corrupt-mirror-copies-journal-files/ "RJF264 from WRC")。   #### 步骤 步骤为: 1. 关闭 Caché 2. 编辑 `/cache.cpf` 文件 3. 重启 Caché 在 cache.cpf 文件中,将以下三行添加到 `[config]` 部分的顶部,其他行保持不变,如下例所示: [config] wduseasyncio=1 asyncwij=8 对于 RHEL Caché(不是 IRIS),还要将以下内容添加到 `[config]` 部分: LibPath=/lib64/rtkaio/ 注意:当 Caché 重新启动后,这些行将在 `[config]` 部分中按字母顺序排序。 ---- ## 总结 本帖给出了创建 900GB LVM PE 条带和为 vSAN 上的数据库磁盘创建文件系统的示例。 为了通过 LVM 条带获得最佳性能,您还学习了如何配置 Caché/InterSystems IRI 来为数据库写入和 WiJ 启用异步 IO。
文章
姚 鑫 · 六月 13, 2021

第六章 控制名称空间的使用

# 第六章 控制名称空间的使用 # 控制名称空间的使用 如将对象投射到`XML`中所述,可以将类分配给名称空间,以便相应的XML元素属于该名称空间,还可以控制类的属性是否也属于该名称空间。 将类中的对象导出为XML时,`%XML.Write`提供其他选项,例如指定元素是否为其父级的本地元素。本节包括以下主题: - 默认情况下,`%XML.Writer`如何处理命名空间 - 如何指定本地元素是否合格 - 如何指定元素是否为其父元素的本地元素 - 如何指定属性是否合格 - 命名空间分配方式的摘要 注意:在InterSystems IRIS XML支持中,可以按类指定名称空间。通常,每个类都有自己的命名空间声明;但是,通常只需要一个或少量的命名空间。还可以在逐个类的基础上指定相关信息(而不是以某种全局方式)。这包括控制元素是否为其父元素的本地元素以及子元素是否合格的设置。为简单起见,建议使用一致的方法。 ## 名称空间的默认处理 若要将启用XML的类分配给命名空间,请设置该类的`Namespace`参数,如将对象投影到XML中所述。在`%XML.Writer`会自动插入命名空间声明,生成命名空间前缀,并在适当的地方应用前缀。例如,以下类定义: ```java Class GXML.Objects.WithNamespaces.Person Extends (%Persistent, %Populate, %XML.Adaptor) { Parameter NAMESPACE = "http://www.person.com"; Property Name As %Name [ Required ]; Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h") [ Required ]; Property GroupID As %Integer(MAXVAL=10,MINVAL=1,XMLPROJECTION="ATTRIBUTE"); } ``` ```java Uberoth,Amanda Q. 1952-01-13 ``` 请注意以下事项: - 名称空间声明被添加到每``元素。 - 默认情况下,``元素的局部元素(``和``)是限定的。 该名称空间被添加为默认名称空间,因此应用于这些元素。 - ``元素的属性(`GroupID`)默认是不限定的。 这个属性没有前缀,因此被认为是未限定的。 - 这里显示的前缀是自动生成的。 (请记住,当对象分配给名称空间时,只指定名称空间,而不是前缀。) - 此输出不会在写入器中设置任何与名称空间相关的属性,也不会在写入器中使用任何与名称空间相关的方法。 ### 命名空间分配的上下文效应 为支持xml的对象分配的名称空间取决于该对象是在顶层导出还是作为另一个对象的属性导出。 一个名为`Address`的类。 假设使用`NAMESPACE`参数将`Address`类分配给名称空间`“http://www.address.org”`。 如果你直接导出`Address`类的一个对象,你可能会收到如下输出: ```java 8280 Main Avenue Washington VT 15355 ``` 注意, `` 元素及其所有元素都在同一个名称空间(`“http://www.address.org”`)中。 相反,假设`Person`类的属性是`Address`对象。 使用`NAMESPACE`参数将`Person`类分配给名称空间`“http://www.person.org”`。 如果导出`Person`类的一个对象,将收到如下输出: ```java Zevon,Samantha H. 1964-05-24 8280 Main Avenue Washington VT 15355 ``` 注意,``元素位于其父对象(`“http://www.person.org”`)的名称空间中。 但是,``的元素位于名称空间`“http://www.address.org”`中。 ## 控制局部元素是否限定 在顶层导出对象时,通常将其视为全局元素。然后根据启用XML的对象的`ELEMENTQUALIFIED`参数的设置处理其本地元素。如果未设置此类参数,则改用编写器属性`ElementQualified`的值;默认情况下,文本格式为1,编码格式为0。 下面的示例显示一个默认设置为`ElementQualified`的对象,即1: ```java Pybus,Gertrude X. 1986-10-19 ``` 该名称空间被添加到``元素中作为默认名称空间,因此应用于元素``和``子元素。 我们修改了写入器定义并将`ElementQualified`属性设置为0。 在本例中,相同的对象如下所示: ```java Pybus,Gertrude X. 1986-10-19 ``` 在本例中,名称空间被添加到带有前缀的``元素中,该前缀用于``元素,但不用于其子元素。 ## 控制一个元素是否局部于它的父元素 默认情况下,当使用`object()`方法生成一个元素并且该元素具有命名空间时,该元素不是其父元素的本地元素。相反,可以强制元素属于其父元素的命名空间。为此,可以使用`object()`方法的可选本地参数;这是第四个参数。 ### 本地参数为0(默认值) 在这里的示例中虑将`NAMESPACE`类参数指定为`“http://www.person.com”`的`Person`类。 如果打开根元素,然后使用`Object()`生成`Person`,则``元素位于`“http://www.person.com”`名称空间中。 以下例子: ```java Adam,George L. 1947-06-29 ``` 如果我们将``元素更深地嵌套到其他元素中,也会出现类似的结果。 ```java Adam,George L. 1947-06-29 ``` ### 局部参数设置为1 为了强制``元素成为其父元素的本地元素,我们将`local`参数设置为1。 如果我们这样做并再次生成前面的输出,我们将收到以下少嵌套版本的输出: ```java Adam,George L. 1947-06-29 ``` 注意,现在``元素在`“http://www.rootns.org”`名称空间中,这是它的父元素的名称空间。 类似地,嵌套程度更高的版本应该是这样的: ```java Adam,George L. 1947-06-29 ``` ## 控制属性是否限定 导出对象时,默认情况下其属性不合格。要使它们合格,请将编写器属性`AttributeQualified`设置为1。下面的示例显示`AttributeQualified`等于0(或尚未设置)的编写器生成的输出: ```java Leiberman,Amanda E. 1988-10-28 ``` 相反,下面的示例显示使用`AttributeQualified`等于1的编写器生成的同一对象: ```java Leiberman,Amanda E. 1988-10-28 ``` 在这两种情况下,元素都是不合格的。 ## 命名空间分配摘要 本节介绍如何为`XML`输出中的任何给定元素确定命名空间。 ### 顶级元素 对于与在顶级导出的InterSystems IRIS类相对应的元素,适用以下规则: 1. 如果为类指定了`Namespace`参数,则元素位于该命名空间中。 2. 如果未指定该参数,则元素位于在生成元素的输出方法(`RootObject()`、`RootElement()`、`Object()`或`Element()`)中指定的命名空间中。 3. 如果未在输出方法中指定命名空间,则元素位于编写器的`DefaultNamespace`属性指定的命名空间中。 4. 如果`DefaultNamespace`属性为空,则元素不在任何命名空间中。 ### 低层元素 要导出的类的子元素受该类的`ELEMENTQUALIFIED`参数影响。如果未设置`ELEMENTQUALIFIED`,则改用编写器属性`ElementQualified`的值;默认情况下,文本格式为1,编码格式为0。 如果元素符合给定类的条件,则该类的子元素将按如下方式分配给命名空间: 1. 如果为父对象指定了`Namespace`参数,则子元素将显式分配给该命名空间。 2. 如果未指定该参数,子元素将显式分配给在生成元素的输出方法(`RootObject()`、`RootElement()`、`Object()`或`Element()`)中指定的命名空间。 3. 如果未在输出方法中指定命名空间,则子元素将显式分配给由编写器的`DefaultNamespace`属性指定的命名空间。 4. 如果`DefaultNamespace`属性为空,则子元素不会显式分配给任何命名空间。
文章
姚 鑫 · 六月 12, 2021

第五章 生成XML元素

# 第五章 生成XML元素 # 生成XML元素 如果使用`RootElement()`启动文档的根元素,则负责生成该根元素内的每个元素。有三个选择: ## 将对象生成为元素 可以从InterSystems IRIS对象生成输出作为元素。在本例中,使用`object()`方法,该方法写入支持XML的对象。输出包括该对象中包含的所有对象引用。可以指定此元素的名称,也可以使用在对象中定义的默认值。 只能在`RootElement()`和`EndRootElement()`方法之间使用`object()`方法。 此示例为给定启用XML的类的所有已保存实例生成输出: ```java /// desc:将表里数据输出本地文件里 /// w ##class(PHA.TEST.Xml).WriteAll("Sample.Person") ClassMethod WriteTableAllToXml(cls As %String = "", directory As %String = "E:\temp\") { if '##class(%Dictionary.CompiledClass).%ExistsId(cls) { Write !, "类不存在或未编译" Quit } s check=$classmethod(cls, "%Extends", "%XML.Adaptor") If 'check { Write !, "类不扩展%XML.Adaptor" Quit } s filename = directory_"Person"_".xml" s writer = ##class(%XML.Writer).%New() s writer.Indent=1 s status = writer.OutputToFile(filename) if $$$ISERR(status) { do $System.Status.DisplayError(status) quit } s status=writer.RootElement("SampleOutput") if $$$ISERR(status) { do $System.Status.DisplayError(status) quit } //获取给定类范围内对象的ID s stmt = ##class(%SQL.Statement).%New() s status = stmt.%PrepareClassQuery(cls,"Extent") if $$$ISERR(status) { do $System.Status.DisplayError(status) quit } s rset = stmt.%Execute() while (rset.%Next()) { //对于每个ID,写入该对象 set objid = rset.%Get("ID") set obj = $CLASSMETHOD(cls,"%OpenId",objid) set status = writer.Object(obj) if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit}} d writer.EndRootElement() d writer.EndDocument() q "" } ``` 此方法的输出包含给定类的所有已保存对象,这些对象嵌套在根元素中。对于`Sample.Person`,输出如下: ```java Tillem,Robert Y. 967-54-9687 1961-11-27 3355 First Court Reston WY 11090 4922 Main Drive Newton NM 98073 Red 47 Waters,Ed X. 361-66-2801 1957-05-29 5947 Madison Drive ... ``` ## 手动构建元素 以手动构造XML元素。在本例中,使用`element()`方法,该方法使用提供的名称写入元素的开始标记。然后,可以编写内容、属性和子元素。使用`EndElement()`方法指示元素的结束。 相关方法如下: ### Element() ```java method Element(tag, namespace As %String) as %Status ``` 写入开始标记。可以为元素提供命名空间,只有在启用了XML的类没有`Namespace`参数的值时才会应用该命名空间。 ### WriteAttribute() ```java method WriteAttribute(name As %String, value As %String = "", namespace As %String, valueNamespace As %String = "", global As %Boolean = 0) as %Status ``` 写入属性。必须指定属性名称和值。参数命名空间是属性名称的命名空间。参数`valueNamespace`是属性值的名称空间;当值在XML模式名称空间中定义时使用。 对于GLOBAL,如果属性在关联的XML架构中是全局的,因此应该有前缀,请指定TRUE。 如果使用此方法,则必须在`Element()`(或`RootElement()`)之后直接使用它。 ### WriteChars() ```java method WriteChars(text) as %Status ``` 写入字符串,执行使该字符串适合作为元素内容所需的任何必要转义。参数必须`%String`类型或`%CharacterStream`类型。 ### WriteCData() ```java method WriteCData(text) as %Status ``` 参数必须`%String`类型或`%CharacterStream`类型。 ### WriteBase64() ```java method WriteBase64(binary) as %Status ``` 将指定的二进制字节编码为`base-64`,并将结果文本写入元素的内容。该参数的类型必须为`%Binary`或`%BinaryStream`。 ### WriteBinHex() ```java method WriteBinHex(binary) as %Status ``` 将指定的二进制字节编码为二进制,并将结果文本写入元素的内容。该参数的类型必须为`%Binary`或`%BinaryStream`。 ### EndElement() ```java method EndElement() as %Status ``` 结束可以与其匹配的元素。 只能在`RootElement()`和`EndRootElement()`方法之间使用这些方法。 注意:这里描述的方法旨在使能够向XML文档编写特定的逻辑片段,但在某些情况下,可能需要更多的控制。`%XML.Writer`类提供了一个附加方法`write()`,可以使用该方法编写任意字符串。有责任确保结果是格式良好的XML文档;不提供任何验证。 示例 下面是一个示例例程: ```java /// w ##class(Demo.XmlDemo).WriteObjXml() ClassMethod WriteObjXml() { set writer=##class(%XML.Writer).%New() set writer.Indent=1 set status=writer.OutputToDevice() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.StartDocument() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.RootElement("root") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.Element("SampleElement") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.WriteAttribute("Attribute","12345") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.Element("subelement") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.WriteChars("yao") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.EndElement() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.Element("subelement") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.WriteChars("xin") if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.EndElement() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.EndElement() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.EndRootElement() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} set status=writer.EndDocument() if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} q "" } ``` ```java DHC-APP>w ##class(Demo.XmlDemo).WriteObjXml() yao xin ``` ### 使用%XMLL.Element 在前一节中,我们使用了Element()并指定了要生成的元素;我们还可以指定名称空间。在某些情况下,类中使用%XML.Element的实例,而不是使用元素名称。此类具有以下属性: - Local属性指定此元素是否为其父元素的本地元素,这会影响命名空间的控制。 - Namespace属性指定此元素的命名空间。 - Tagname属性指定此元素的名称。 这里还可以使用前面描述的WriteAttribute()方法。
文章
姚 鑫 · 六月 11, 2021

第四章 添加命名空间声明

# 第四章 添加命名空间声明 # 添加命名空间声明 ## 默认行为 在`%XML.Writer`会自动插入命名空间声明,生成命名空间前缀,并在适当的地方应用前缀。例如,以下类定义: ```java Class Sample.Person Extends (%Persistent, %Populate, %XML.Adaptor) { Parameter NAMESPACE = "http://www.yaoxin.com"; } ``` 如果导出此类的多个对象,则会看到类似以下内容: ```java DHC-APP> w ##class(Demo.XmlDemo).Obj2Xml(1) yaoxin 111-11-1117 1990-04-25 889 Clinton Drive St Louis WI 78672 9619 Ash Avenue Ukiah AL 56589 濮氶懌 111-11-1115 Red Orange Yellow Green Red Orange Yellow 31 ``` 名称空间声明会自动添加到每个`` 元素。只将其添加到文档的根目录。 ## 手动添加声明 可以控制何时将命名空间引入XML输出。以下方法都会影响所写入的下一个元素(但不会影响该元素之后的任何元素)。为方便起见,其中几种方法添加了标准的`W3`名称空间。 通常使用这些方法将命名空间声明添加到文档的根元素;也就是说,在调用`RootObject()`或`RootElement()`之前调用其中一个或多个方法。 注意:这些方法都没有将任何元素分配给名称空间,并且这些名称空间永远不会作为默认名称空间添加。在生成特定元素时,需要指明它使用的名称空间,如后面的“编写根元素”和“生成XML元素”中所述。 ### AddNamespace() ```java method AddNamespace(namespace As %String, prefix As %String, schemaLocation As %String) as %Status ``` 添加指定的命名空间。这里,`Namespace`是要添加的名称空间,`Prefix`是该名称空间的可选前缀,`schemaLocation`是指示相应架构位置的可选URI。 如果未指定前缀,则会自动生成前缀(格式为S01、S02等)。 下面的示例显示了此方法的效果。首先,假设`Person`类被分配给一个名称空间(类参数中的`NAMESPACE`)。如果在未首先调用`AddNamespace()`方法的情况下生成此类实例的输出,则可能会收到如下所示的输出: ```java Love,Bart Y. ... ``` 或者,在编写根元素之前按如下方式调用`AddNamespace()`方法: ```java set status=writer.AddNamespace("http:///www.person.org","p") ``` 如果随后生成根元素,则输出如下所示: ```java ... ``` 或者,假设在调用`AddNamespace()`方法时指定了第三个参数,该参数提供了关联架构的位置: ```java set status=writer.AddNamespace("http:///www.person.org","p","http://www.MyCompany.com/schemas/person.xsd") ``` 在这种情况下,如果随后生成Root元素,则输出如下所示: ```java ... ``` ### AddInstanceNamespace() ```java method AddInstanceNamespace(prefix As %String) as %Status ``` 添加W3架构实例命名空间。这里的前缀是用于此命名空间的可选前缀。默认前缀为`XSI`。 ```java ... ``` ### AddSchemaNamespace() ```java method AddSchemaNamespace(prefix As %String) as %Status ``` 添加`W3`架构命名空间。这里的前缀是用于此命名空间的可选前缀。默认前缀为`s`。 ```java ... ``` ### AddSOAPNamespace() ```java method AddSOAPNamespace(soapPrefix As %String, schemaPrefix As %String, xsiPrefix As %String) as %Status ``` 添加`W3 SOAP`编码命名空间、`SOAP`架构命名空间和`SOAP`架构实例命名空间。此方法有三个可选参数:用于这些命名空间的前缀。默认前缀分别为`SOAP-Enc`、`s`和`XSI`。 ```java ... ``` ### AddSOAP12Namespace() ```java method AddSOAP12Namespace(soapPrefix As %String, schemaPrefix As %String, xsiPrefix As %String) as %Status ``` 添加`W3 SOAP 1.2`编码命名空间、`SOAP`架构命名空间和`SOAP`架构实例命名空间。 ```java ... ``` 可以使用这些方法中的多个方法。如果使用其中的多个命名空间,则受影响的元素将包含所有指定命名空间的声明。 # 编写根元素 每个XML文档必须恰好包含一个根元素。有两种方法可以创建此元素: - 根元素可能直接对应于一个启用了InterSystems IRIS XML的对象。 在本例中,使用`RootObject()`方法,该方法将指定的启用XML的对象作为根元素写入。输出包括该对象中包含的所有对象引用。根元素获取该对象的结构,不能插入其他元素您可以指定根元素的名称,也可以使用由启用XML的对象定义的默认值。 前面的示例使用了此技术。 - 根元素可能只是一组元素的包装器(可能是一组支持XML的对象)。 在本例中,使用`RootElement()`方法,该方法插入具有指定名称的根级元素。如果此文档缩进,此方法还会增加后续操作的缩进级别。 然后调用其他方法为根元素内的一个或多个元素生成输出。在根目录中,可以按照选择的任何顺序或逻辑包含所需的元素。之后,调用`EndRootElement()`方法关闭根元素。 在这两种情况下,都可以指定要用于根元素的命名空间,只有在启用了`XML`的类没有`Namespace`参数值的情况下才会应用该命名空间。 请记住,如果文档包含文档类型声明,则该`DTD`的名称必须与根元素的名称相同。