文章
· 一月 4, 2023 阅读大约需 6 分钟

解析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(&quot;/REQUEST/KSBM&quot;)" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value="&quot;select * from whkx_oas_operation_dept&quot;" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value="&quot;whkx_oas_operation_dept&quot;" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value="&quot;Query&quot;" 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(&quot;/REQUEST/KSBM&quot;)" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value="&quot;SELECT DISTINCT ORDERED_EMP_CODE  FROM core_his50.HIS_DEPT_INCOME_MONTH_I_H080 WHERE  HIS_PATIENT_ID = 'ZY010000000039'&quot;" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value="&quot;HIS_DEPT_INCOME_MONTH_I_H080&quot;" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value="&quot;Query&quot;" 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(&quot;/REQUEST/KSBM&quot;)" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value="&quot;SELECT * FROM core_his50.His_dict_dept_H080&quot;" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value="&quot;core_his50.His_dict_dept_H080&quot;" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value="&quot;Query&quot;" 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(&quot;/REQUEST/KSBM&quot;)" action="set" xpos='200' ypos='250' >
<annotation><![CDATA[设定查询参数]]></annotation>
</assign>
<assign name="设定SQL脚本" property="context.sqlstatement" value="&quot;SELECT * FROM His_dict_dept_H080&quot;" action="set" xpos='200' ypos='350' >
<annotation><![CDATA[设定SQL脚本]]></annotation>
</assign>
<assign name="设定数据库表名" property="context.tablename" value="&quot;dhis.His_dict_dept_H080&quot;" action="set" xpos='200' ypos='450' >
<annotation><![CDATA[设定数据库表名]]></annotation>
</assign>
<assign name="设定SQL类型" property="context.sqltype" value="&quot;Query&quot;" 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>
}

}
  • 测试结果

image

  • 参考
    image

%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
}

工程分支节点生成及查询测试

  • 测试结果
    image

  • 通过存储过程查询

call BOE_TEST.ClassAnalysis_GetMsgInfo()

image

讨论 (0)1
登录或注册以继续