解析BP中的XData获取Switch-Case-Call Xml节点信息
一、目的
因使用BP中Switch分支来区分不同节点(即接口)及流向,个人已知方法中无相关统计功能能直接获取各分支节点及流向BO(调用第三方系统)信息,且当前使用系统未封装相关模块供查询,故通过解析BP中XData的方式获取Switch-Case节点及Call调用相关信息
二、解析类中的XData数据
/// 解析类中的XData内容
/// SELECT * FROM %Dictionary.CompiledXData
/// xdataID XData表ID
/// d ##class(BOE.TEST.ClassAnalysis).XDataAnalysisTextReader("JHIP.SM.BP.View||BPL")
ClassMethod XDataAnalysisTextReader(xdataID As %String) As %Status
{
//获取XData流
s compiledXdata=##class(%Dictionary.CompiledXData).%OpenId(xdataID)
s tStream=compiledXdata.Data
If '$IsObject(tStream) s tSC=%objlasterror q
//逐行读取xml
s status=##class(%XML.TextReader).ParseStream(tStream,.textreader)
if $$$ISERR(status) do $System.Status.DisplayError(status) q
s conditionMsgCode="sy"
while textreader.Read()
{
//节点类型为element
if (textreader.NodeType="element"){
//节点路径中包含/switch/case且case为结尾
if ((textreader.Path["/switch/case")&&(textreader.Path'["/switch/case/")){ //接口switch case解析接口 element
//节点有属性
if (textreader.HasAttributes){
//移动到对应的属性节点Attribute
if (textreader.MoveToAttributeName("condition")){
s condition=textreader.Value
s len=$l(condition,"||")
for i=1:1:len{
s tepCondition=$p(condition,"||",i)
if (tepCondition["'="){
s conditionMsgCode=$tr($p(tepCondition,"action",2),"""")
if (conditionMsgCode=""){
s conditionMsgCode=$tr($p(tepCondition,"OriginalDocId",2),"""")
}
}else{
s conditionMsgCode=$tr($p(tepCondition,"=",2),"""")
}
}
//b:conditionMsgCode=""
s conditionMsgCode=$tr(conditionMsgCode,"()")
if (conditionMsgCode=""){ //如果未定义分支条件,则设置为类名
s conditionMsgCode=xdataID
}
//移动到下一个节点Node
d textreader.Read()
if (textreader.HasAttributes){
if (textreader.MoveToAttributeName("name")){
s name=textreader.Value
s ^sy(conditionMsgCode)=name
}
}else{
s ^sy(conditionMsgCode)=""
}
}
}
}
if ((textreader.Path["/switch/case/")&&(textreader.Path["/call")&&(textreader.Path'["/call/")){ //接口switch case call解析接口 element
s callName="",callTarget=""
if (textreader.HasAttributes){
if (textreader.MoveToAttributeName("name")){
s callName=textreader.Value
s ^sy(conditionMsgCode,"callName",callName)=callName
}
if (textreader.MoveToAttributeName("target")){
s callTarget=textreader.Value
s ^sy(conditionMsgCode,"callTarget",callTarget)=callTarget
}
}
}
}
}
}
XData解析测试
- 测试用BP结构
Class JHIP.SM.BP.View Extends Ens.BusinessProcessBPL
{
/// BPL Definition
XData BPL [ XMLNamespace = "http://www.intersystems.com/bpl" ]
{
<process language='objectscript' request='Ens.Request' response='Ens.Response' height='2000' width='2015' >
<context>
<property name='sqltype' type='%String' initialexpression='"Query"' instantiate='0' >
<parameters>
<parameter name='MAXLEN' value='50' />
</parameters>
</property>
<property name='sqlstatement' type='%String' instantiate='0' >
<parameters>
<parameter name='MAXLEN' value='1000' />
</parameters>
</property>
<property name='tablename' type='%String' instantiate='0' >
<parameters>
<parameter name='MAXLEN' value='50' />
</parameters>
</property>
<property name='sql' type='JHIPLIB.SQL.MSG.SQLMessage' instantiate='0' />
<property name='sqlparameter' type='%String' instantiate='0' >
<parameters>
<parameter name='MAXLEN' value='50' />
</parameters>
</property>
</context>
<sequence xend='200' yend='600' >
<switch name='判断接口' xpos='200' ypos='250' xend='200' yend='500' >
<case condition='request.OriginalDocId="JH1301"' >
<sequence name='JH1301手麻测试' xpos='335' ypos='400' xend='200' yend='850' >
<assign name="设定查询参数" property="context.sqlparameter" value="request.GetValueAt("/REQUEST/KSBM")" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value=""select * from whkx_oas_operation_dept"" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value=""whkx_oas_operation_dept"" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value=""Query"" action="set" xpos='200' ypos='550' >
<annotation><![CDATA[有QUERY、INSERT、UPDATE、DELETE4种]]></annotation>
</assign>
<code name='拼接sql脚本生成xml消息' xpos='200' ypos='650' >
<annotation><![CDATA[拼接sql脚本生成xml消息]]></annotation>
<![CDATA[
Set sqlreq=##class(JHIPLIB.SQL.MSG.SQLMessage).%New()
Set context.sqlstatement=$replace(context.sqlstatement,"?",context.sqlparameter)
Set sqlreq.sqlreq=context.sqlstatement
Set sqlreq.sqltype=context.sqltype
Set sqlreq.tablename=context.tablename
Set context.sql=sqlreq
]]>
</code>
<call name='查询手麻视图服务1' target='测试服务BO' async='0' xpos='200' ypos='750' >
<annotation><![CDATA[查询手麻视图服务1]]></annotation>
<request type='Ens.Request' >
<assign property="callrequest" value="context.sql" action="set" />
</request>
<response type='Ens.Response' >
<assign property="response" value="callresponse" action="set" />
</response>
</call>
</sequence>
</case>
<case condition='request.OriginalDocId="JH1302"' >
<sequence name='his测试' xpos='605' ypos='400' xend='200' yend='850' >
<assign name="设定查询参数" property="context.sqlparameter" value="request.GetValueAt("/REQUEST/KSBM")" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value=""SELECT DISTINCT ORDERED_EMP_CODE FROM core_his50.HIS_DEPT_INCOME_MONTH_I_H080 WHERE HIS_PATIENT_ID = 'ZY010000000039'"" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value=""HIS_DEPT_INCOME_MONTH_I_H080"" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value=""Query"" action="set" xpos='200' ypos='550' >
<annotation><![CDATA[有QUERY、INSERT、UPDATE、DELETE4种]]></annotation>
</assign>
<code name='拼接sql脚本生成xml消息' xpos='200' ypos='650' >
<annotation><![CDATA[拼接sql脚本生成xml消息]]></annotation>
<![CDATA[
Set sqlreq=##class(JHIPLIB.SQL.MSG.SQLMessage).%New()
Set context.sqlstatement=$replace(context.sqlstatement,"?",context.sqlparameter)
Set sqlreq.sqlreq=context.sqlstatement
Set sqlreq.sqltype=context.sqltype
Set sqlreq.tablename=context.tablename
Set context.sql=sqlreq
]]>
</code>
<call name='查询手麻视图服务2' target='his测试BO' async='0' xpos='200' ypos='750' >
<annotation><![CDATA[查询手麻视图服务1]]></annotation>
<request type='Ens.Request' >
<assign property="callrequest" value="context.sql" action="set" />
</request>
<response type='Ens.Response' >
<assign property="response" value="callresponse" action="set" />
</response>
</call>
</sequence>
</case>
<case condition='request.OriginalDocId="JH0000"' >
<sequence name='JH000001' xpos='875' ypos='400' xend='200' yend='850' >
<assign name="设定查询参数" property="context.sqlparameter" value="request.GetValueAt("/REQUEST/KSBM")" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value=""SELECT * FROM core_his50.His_dict_dept_H080"" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value=""core_his50.His_dict_dept_H080"" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value=""Query"" action="set" xpos='200' ypos='550' >
<annotation><![CDATA[有QUERY、INSERT、UPDATE、DELETE4种]]></annotation>
</assign>
<code name='拼接sql脚本生成xml消息' xpos='200' ypos='650' >
<annotation><![CDATA[拼接sql脚本生成xml消息]]></annotation>
<![CDATA[
Set sqlreq=##class(JHIPLIB.SQL.MSG.SQLMessage).%New()
Set context.sqlstatement=$replace(context.sqlstatement,"?",context.sqlparameter)
Set sqlreq.sqlreq=context.sqlstatement
Set sqlreq.sqltype=context.sqltype
Set sqlreq.tablename=context.tablename
Set context.sql=sqlreq
]]>
</code>
<call name='查询手麻视图服务3' target='his测试BO' async='0' xpos='200' ypos='750' >
<annotation><![CDATA[查询手麻视图服务1]]></annotation>
<request type='Ens.Request' >
<assign property="callrequest" value="context.sql" action="set" />
</request>
<response type='Ens.Response' >
<assign property="response" value="callresponse" action="set" />
</response>
</call>
</sequence>
</case>
<case condition='request.OriginalDocId="JH0000"' >
<sequence name='JH000002' xpos='1145' ypos='400' xend='200' yend='850' disabled="true">
<assign name="设定查询参数" property="context.sqlparameter" value="request.GetValueAt("/REQUEST/KSBM")" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value=""SELECT * FROM His_dict_dept_H080"" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value=""dhis.His_dict_dept_H080"" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value=""Query"" action="set" xpos='200' ypos='550' >
<annotation><![CDATA[有QUERY、INSERT、UPDATE、DELETE4种]]></annotation>
</assign>
<code name='拼接sql脚本生成xml消息' xpos='200' ypos='650' >
<annotation><![CDATA[拼接sql脚本生成xml消息]]></annotation>
<![CDATA[
Set sqlreq=##class(JHIPLIB.SQL.MSG.SQLMessage).%New()
Set context.sqlstatement=$replace(context.sqlstatement,"?",context.sqlparameter)
Set sqlreq.sqlreq=context.sqlstatement
Set sqlreq.sqltype=context.sqltype
Set sqlreq.tablename=context.tablename
Set context.sql=sqlreq
]]>
</code>
<call name='查询手麻视图服务1' target='测试服务BO' async='1' xpos='200' ypos='750' >
<annotation><![CDATA[查询手麻视图服务1]]></annotation>
<request type='Ens.Request' >
<assign property="callrequest" value="context.sql" action="set" />
</request>
<response type='Ens.Response' >
<assign property="response" value="callresponse" action="set" />
</response>
</call>
</sequence>
</case>
<case condition='request.action="JH1401"' >
<call name='HTTP测试' target='测试HTTP样例BO' async='1' xpos='1415' ypos='400' >
<request type='Ens.Request' >
<assign property="callrequest" value="request" action="set" />
</request>
<response type='Ens.Response' >
<assign property="response" value="callresponse" action="set" />
</response>
</call>
</case>
<default name='default' />
</switch>
</sequence>
</process>
}
Storage Default
{
<Type>%Storage.Persistent</Type>
}
}
- 测试结果
- 参考
%XML.TextReader逐个节点地读取和解析文档。
%XML.XPATH.document使用引用文档中特定节点的XPATH表达式来获取数据。
[XMLTools参考链接](%3Cdiv align="justify" style="min-height: 13pt; "%3E%3Ca href="https://docs.intersystems.com/irisforhealth20222/csp/docbook/DocBook.UI...."%3E%3Cfont face="Calibri" color="#0000ff" size="2"%3E%3Cspan dir="ltr" style=" "%3E%3Cu%3Ehttps://docs.intersystems.com/irisforhealth20222/csp/docbook/DocBook.UI....)
三、获取工程下所有BP类型类文件
/// 获取工程下所有BP类型类文件
/// SELECT * FROM %Studio.Project
/// package:包名称
/// w ##class(BOE.TEST.ClassAnalysis).GetClassNameByPackage()
ClassMethod GetClassNameByPackage(package As %String = "") As %String
{
s $zt="Exception"
k ^sy //初始化,Global用于存储分支节点相关信息
s project=""
for{
s project=$o(^oddPROJECT(project))
q:project=""
s rs=##class(%Library.ResultSet).%New("%Studio.Project:ProjectItemsList")
//s columns=rs.GetColumnCount()
s sc=rs.Execute(project)
while(rs.Next()){
s i=0
s name=rs.GetData(2) //Item名称
s type=rs.GetData(3) //Item类型
s tempPackage=rs.GetData(5) //包名
if type="CLS"{ //类文件
s theCompiledClassObj = ##Class(%Dictionary.CompiledClass).%OpenId(name)
continue:theCompiledClassObj=""
s primarySuper=theCompiledClassObj.PrimarySuper
continue:primarySuper'["Ens.BusinessProcess" //只处理BP
if (package'=""){
for j=1:1:$L(name,"."){
if $P(name,".",j)=package s i=1 //过滤包名
}
continue:i=0
}
s xDataId=""
&sql(SELECT top 1 ID into :xDataId FROM %Dictionary.CompiledXData WHERE parent=:name)
if (xDataId'=""){
//解析XData
d ##class(BOE.TEST.ClassAnalysis).XDataAnalysisTextReader(xDataId)
}
}
}
}
q 1
Exception
q "-1^"_$ze
}
查询已生成的分支节点数据
/// 查询接口目录
/// d ##class(%Results).RunQuery("BOE.TEST.ClassAnalysis","GetMsgInfo")
Query GetMsgInfo() As %Query(ROWSPEC = "msgCode,msgDesc,callName,callTarget") [ SqlProc ]
{
}
ClassMethod GetMsgInfoExecute(ByRef qHandle As %Binary) As %Status
{
s repid=$I(^CacheTemp)
s ind=1
s qHandle=$lb(0,repid,0)
s msgCode=""
for{
s msgCode=$o(^sy(msgCode)) //接口编码
q:msgCode=""
s msgDesc=^sy(msgCode) //接口描述
s callName="",callTarget=""
for{
s callName=$o(^sy(msgCode,"callName",callName))
q:callName=""
d OutRow
}
}
Quit $$$OK
OutRow
s Data=$lb(msgCode,msgDesc,callName,callTarget)
s ^CacheTemp(repid,ind)=Data
s ind=ind+1
quit
}
ClassMethod GetMsgInfoFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = GetBISQCIndexDataExecute ]
{
s AtEnd=$LIST(qHandle,1)
s repid=$LIST(qHandle,2)
s ind=$LIST(qHandle,3)
s ind=$o(^CacheTemp(repid,ind))
If ind="" { // if there are no more rows, finish fetching
s AtEnd=1
s Row=""
}
Else {
s Row=^CacheTemp(repid,ind)
}
s qHandle=$lb(AtEnd,repid,ind)
Quit $$$OK
}
ClassMethod GetMsgInfoClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = GetBISQCIndexDataExecute ]
{
s repid=$LIST(qHandle,2)
Kill ^CacheTemp(repid)
Quit $$$OK
}
工程分支节点生成及查询测试
-
测试结果
-
通过存储过程查询
call BOE_TEST.ClassAnalysis_GetMsgInfo()