Pesquisar

Resumo
· Set. 17, 2024

Final Call: Employee-Only Video Demos Contest!

Dear colleague,

This is your final call to enter the Employee-Only Video Demos Contest! 🎥 You have until September 22, to create and upload your demo video (up to 10 minutes) on any topic related to InterSystems products and services.  

Every participant is guaranteed a gift, and you also stand a chance to be one of the contest winners! 🎁

For more info, including contest guidelines and prizes, please check out the Insider Article.

Don’t miss out – show off your skills and creativity! 

Pergunta
· Set. 17, 2024

Error al transformar de XML a ER7 con esquema HL7 personalizado que hemos creado

Buenos días,

En una integración que estamos haciendo entre dos sistemas recibos un ORU_R01 con los datos de un monitor.  Lo recibimos mediante una llamada a nuestro webservice en formato XML.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="http://com.gacelacare.ws">
   <soapenv:Header/>
   <soapenv:Body>
      <com:processMessage>
         <String_1><![CDATA[<ORU_R01 xmlns="urn:hl7-org:v2xml">
    <MSH>
        <MSH.1>|</MSH.1>
        <MSH.2> ^~\&amp;amp;</MSH.2>
        <MSH.3>
            <HD.1>AA</HD.1>
        </MSH.3>
        <MSH.4>
            <HD.1>07</HD.1>
        </MSH.4>
        <MSH.5>
            <HD.1>GCXXX</HD.1>
        </MSH.5>
        <MSH.6>
            <HD.1>07</HD.1>
        </MSH.6>
        <MSH.7>
            <TS.1>20240718110036</TS.1>
        </MSH.7>
        <MSH.9>
            <MSG.1>ORU</MSG.1>
            <MSG.2>R01</MSG.2>
            <MSG.3>ORU_R01</MSG.3>
        </MSH.9>
        <MSH.10>2024071811003601100091714521-C67ADEEC5009447AB2A822A92E7061E9</MSH.10>
        <MSH.11>
            <PT.1>P</PT.1>
        </MSH.11>
        <MSH.12>
            <VID.1>2.5</VID.1>
        </MSH.12>
        <MSH.15>AL</MSH.15>
        <MSH.16>ER</MSH.16>
    </MSH>
    <ORU_R01.PATIENT_RESULT>
        <ORU_R01.PATIENT>
            <PID>
                <PID.1>1</PID.1>
                <PID.3>
                    <CX.1>2222222222</CX.1>
                </PID.3>
            </PID>
            <ORU_R01.VISIT>
                <PV1>
                    <PV1.1>2222222222</PV1.1>
                </PV1>
            </ORU_R01.VISIT>
        </ORU_R01.PATIENT>
        <ORU_R01.ORDER_OBSERVATION>
            <OBR>
                <OBR.1>1</OBR.1>
                <OBR.4>
                    <CE.1>AA</CE.1>
                    <CE.2>AA</CE.2>
                </OBR.4>
                <OBR.10>
                    <XCN.1>11111111V</XCN.1>
                </OBR.10>
                <OBR.25>F</OBR.25>
                <OBR.34>
                    <NDL.1>
                        <CNN.1>11111111V</CNN.1>
                    </NDL.1>
                </OBR.34>
            </OBR>
            <ORU_R01.OBSERVATION>
                <OBX>
                    <OBX.2>CE</OBX.2>
                    <OBX.3>
                        <CE.1>35570</CE.1>
                        <CE.2>Font O2</CE.2>
                        <CE.3>DIC</CE.3>
                    </OBX.3>
                     <OBX.5 LongName="Observation Value">
                        <CE.1>UNAF</CE.1>
                        <CE.2>Ulleres nasals d alt flux</CE.2>
                    </OBX.5>
                    <OBX.3>
                        <CE.1>35570</CE.1>
                        <CE.2>Font O2</CE.2>
                        <CE.3>DIC</CE.3>
                    </OBX.3>
                    <OBX.6>
                        <CE.1>.</CE.1>
                        <CE.2>.</CE.2>
                        <CE.3>DIC</CE.3>
                    </OBX.6>
                    <OBX.11>F</OBX.11>
                    <OBX.14>
                        <TS.1>20240718110036</TS.1>
                    </OBX.14>
                    <OBX.16>
                        <XCN.1>11111111V</XCN.1>
                    </OBX.16>
                    <OBX.18>
                        <EI.1>100091714521</EI.1>
                    </OBX.18>
                </OBX>
            </ORU_R01.OBSERVATION>
            <ORU_R01.OBSERVATION>
				<OBX>
					<OBX.1>5</OBX.1>
					<OBX.2>NM</OBX.2>
					<OBX.3>
						<CE.1>TEMP</CE.1>
						<CE.2>Temperatura C</CE.2>
						<CE.3>ICS</CE.3>
					</OBX.3>
					<OBX.5>36.3599</OBX.5>
					<OBX.6>
						<CE.1>C</CE.1>
						<CE.2>Grados centigrados</CE.2>
						<CE.3>ICS</CE.3>
					</OBX.6>
					<OBX.11>F</OBX.11>
					<OBX.14>
						<TS.1>20230213102353</TS.1>
					</OBX.14>
					<OBX.16>
						<XCN.1>43526320Q</XCN.1>
					</OBX.16>
					<OBX.18>
						<EI.1>100033553418</EI.1>
					</OBX.18>
				</OBX>
			</ORU_R01.OBSERVATION>
        </ORU_R01.ORDER_OBSERVATION>
    </ORU_R01.PATIENT_RESULT>
</ORU_R01>]]></String_1>
      </com:processMessage>
   </soapenv:Body>
</soapenv:Envelope>

 

Luego en nuestra clase lo convertimos a HL7 en formato pipe, tanto para realizar cambios en determinados campos cómo para enviar a otros sistemas. Uno de los sitemas a los que tenemos que enviar el ORU también lo espera en formato XML, por lo que después de hacer los cambios volvemos a transformarlo a XML.

El problema que se nos ha presentado ahora es que nos han empezado a enviar variables en el que el segmento OBX.5 estamos recibiendo una estructura de datos, en lugar de sólo el valor cómo hasta ahora:

Antes:

<OBX.5>115</OBX.5>

Ahora algunas variables, No todas, contienen una estructura de datos:

<OBX.5 LongName="Observation Value">
    <CE.1>UNAF</CE.1>
    <CE.2>Ulleres nasals d alt flux</CE.2>
</OBX.5>

Y cómo en el esquema de HL7 2.5 que viene definido con IRIS espera que el OBX.5 sea un valor:

al transformarlo de fortamo pipe a formato XML lo hace cómo un valor y no estructura: <OBX.5>TUBT^Tub en T</OBX.5> lo que provocar un error en el sistema que recibe el ORU en formato XML .

<ORU_R01.OBSERVATION><OBX><OBX.1 LongName="Set ID - OBX"></OBX.1><OBX.2 LongName="Value Type">CE</OBX.2><OBX.3 LongName="Observation Identifier"><CE.1 LongName="identifier">35570</CE.1><CE.2 LongName="text">Font O2</CE.2><CE.3 LongName="name of coding system">ICS</CE.3></OBX.3><OBX.5>TUBT^Tub en T</OBX.5><OBX.6 LongName="Units"><CE.1 LongName="identifier">.</CE.1><CE.2 LongName="text">.</CE.2><CE.3 LongName="">ICS</CE.3></OBX.6><OBX.11 LongName="Observation Result Status">F</OBX.11><OBX.14><TS.1>20240610125836</TS.1></OBX.14><OBX.16>2563464401</OBX.16><OBX.18><EI.1>100091714521</EI.1></OBX.18></OBX></ORU_R01.OBSERVATION>

No sabemos si es la mejor opción, pero para intentar solucionar este problema, hemos creado un esquema HL7 personalizada para que  el OBX.5 sea estructurado:

<Category name="GACELA.2.5.v2" base="2.5">

<MessageType name='ORU_R01' structure='ORU_R01' returntype='base:ACK_R01' description='Unsolicited transmission of an observation message - ORU Subscription (Response)'/>

<MessageStructure name='ORU_R01' definition='base:MSH~[~{~base:SFT~}~]~{~[~base:PID~[~base:PD1~]~[~{~base:NTE~}~]~[~{~base:NK1~}~]~[~base:PV1~[~base:PV2~]~]~]~{~[~base:ORC~]~base:OBR~[~{~base:NTE~}~]~[~{~base:TQ1~[~{~base:TQ2~}~]~}~]~[~base:CTD~]~[~{~OBX~[~{~base:NTE~}~]~}~]~[~{~base:FT1~}~]~[~{~base:CTI~}~]~[~{~base:SPM~[~{~OBX~}~]~}~]~}~}~[~base:DSC~]'/>

<SegmentStructure name='OBX' description='Observation/Result'>
    <SegmentSubStructure piece='1' description='Set ID - OBX' datatype='base:SI' max_length='4' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='2' description='Value Type' datatype='base:ID' symbol='?' max_length='2' required='C' ifrepeating='0' codetable='base:125'/>
    <SegmentSubStructure piece='3' description='Observation Identifier' datatype='base:CE' symbol='!' max_length='250' required='R' ifrepeating='0'/>
    <SegmentSubStructure piece='4' description='Observation Sub-ID' datatype='base:ST' symbol='?' max_length='20' required='C' ifrepeating='0'/>
    <SegmentSubStructure piece='5' description='Observation Value' datatype='base:CE' max_length='250' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='6' description='Units' datatype='base:CE' max_length='250' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='7' description='References Range' datatype='base:ST' max_length='60' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='8' description='Abnormal Flags' datatype='base:IS' symbol='*' max_length='5' required='O' ifrepeating='1' codetable='base:78'/>
    <SegmentSubStructure piece='9' description='Probability' datatype='base:NM' max_length='5' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='10' description='Nature of Abnormal Test' datatype='base:ID' symbol='*' max_length='2' required='O' ifrepeating='1' codetable='base:80'/>
    <SegmentSubStructure piece='11' description='Observation Result Status' datatype='base:ID' symbol='!' max_length='1' required='R' ifrepeating='0' codetable='base:85'/>
    <SegmentSubStructure piece='12' description='Effective Date of Reference Range' datatype='base:TS' max_length='26' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='13' description='User Defined Access Checks' datatype='base:ST' max_length='20' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='14' description='Date/Time of the Observation' datatype='base:TS' max_length='26' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='15' description='Producer&apos;s ID' datatype='base:CE' max_length='250' required='O' ifrepeating='0'/>
    <SegmentSubStructure piece='16' description='Responsible Observer' datatype='base:XCN' symbol='*' max_length='250' required='O' ifrepeating='1'/>
    <SegmentSubStructure piece='17' description='Observation Method' datatype='base:CE' symbol='*' max_length='250' required='O' ifrepeating='1'/>
    <SegmentSubStructure piece='18' description='Equipment Instance Identifier' datatype='base:EI' symbol='*' max_length='22' required='O' ifrepeating='1'/>
    <SegmentSubStructure piece='19' description='Date/Time of the Analysis' datatype='base:TS' max_length='26' required='O' ifrepeating='0'/>
</SegmentStructure>

</Category>

En nuestro Webservice intentamos hacer la transformación de XML a HL7 utilizando este nuevo esquema:

Class WEBSERVICES.IWSReceiverEJBEndPointPort Extends (EnsLib.SOAP.Service) [ ProcedureBlock ]
{

/// This is the namespace used by the Service
Parameter NAMESPACE = "http://xxxxx.ws"; /// Use xsi:type attribute for literal types.
Parameter OUTPUTTYPEATTRIBUTE = 0; /// Determines handling of Security header.
Parameter SECURITYIN = "ALLOW"; /// This is the name of the Service
Parameter SERVICENAME = "ws_receiver"; /// This is the SOAP version supported by the service.
Parameter SOAPVERSION = 1.1; /// Namespaces of referenced classes will be used in the WSDL.
Parameter USECLASSNAMESPACES = 0; /// Non-default use of element/type attribute in parts.
Parameter XMLELEMENT = 0;

...

Method processMessage(String1 As %CacheString(XMLNAME="String_1")) As %CacheString(XMLNAME="result") [ Final, ProcedureBlock = 1, SoapAction = "", SoapBindingStyle = rpc, SoapBodyUse = literal, WebMethod ]
{
   ....

  s hl7 = ##class(EnsLib.HL7.Message).%New()
  s hl7 = ##class(ITB.HL7.Util.Convert).XMLToER7(xml,.sc,"GACELA.2.5.v2") $$$ThrowOnError(sc)

...

}

Al intentar utilizar nuestra esquema customizado nos da el siguiente error:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://www.w3.org/2001/XMLSchema">
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring>Server Application Error</faultstring>
         <detail>
            <Exception>ERROR #6301: SAX XML Parser Error: &lt;INVALID OREF>zendElement+21^ITB.HL7.Format.HL7XMLv2.1             if (..%SegObj.GetValueAt(..%FieldPath)="") { while processing Anonymous Stream at line 3 offset 25</Exception>
         </detail>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Utilizando el esquema HL7 2.5 si que hace correctamente la transformación:

s hl7 = ##class(ITB.HL7.Util.Convert).XMLToER7(xml,.sc,"2.5") $$$ThrowOnError(sc)

¿Sabéis porque nos da este error al intentar utilizar nuestra esquema? ¿Hay algún error en la definición o en el uso del esquema para la transformación?

Tampoco sabemos si la aproximación que hemos hecho es la correcta para resolver el problema que tenemos con el OBX.5 , porque recibimos variables con los dos formatos: sólo valor o estructurado. ¿Hay una mejor manera de afrontar este problema?

Agradecemos de antemano cualquier ayuda que nos podáis ofrecer.

Saludos cordiales,

Oscar

6 Comments
Discussão (6)3
Entre ou crie uma conta para continuar
Anúncio
· Set. 17, 2024

L'examen InterSystems IRIS SQL Specialist est désormais LIVE !

Bonjour la Communauté,

L'équipe de certification d'InterSystems Learning Services est ravie d'annoncer la sortie de notre nouvel examen InterSystems IRIS SQL Specialist. Il est désormais disponible à l'achat et à la planification dans le catalogue d'examens InterSystems. Les candidats potentiels peuvent consulter les sujets d'examen et les questions de pratique pour les aider à s'orienter vers les approches et le contenu des questions d'examen. Les candidats qui réussissent l'examen recevront un badge de certification numérique qui peut être partagé sur des comptes de réseaux sociaux comme LinkedIn.

Si vous êtes nouveau dans la certification InterSystems, veuillez consulter nos pages de programme qui incluent des informations sur la passation des examens, les politiques d'examen, la FAQ et plus encore. Consultez également notre certification organisationnelle, qui peut aider votre organisation à accéder à de précieuses opportunités commerciales et à s'établir comme un fournisseur fiable de solutions InterSystems sur notre marché.

Si vous avez des idées sur la création de nouvelles certifications qui peuvent vous aider à faire progresser votre carrière, l'équipe de certification d'InterSystems Learning Services est toujours ouverte aux idées et suggestions. Veuillez nous contacter à l'adresse certification@intersystems.com si vous souhaitez partager vos idées.

Discussão (0)1
Entre ou crie uma conta para continuar
Pergunta
· Set. 17, 2024

Get a specific value from an ASTM segment in Routing Rule

Hello.

I have a business process with an "ASTM" class : 

Inside this process i have a business rule. Inside this rule i want to get a specific field inside the message :

So i will use the same logic for HL7 messages. Here is the "path" to the segment and the field : 

So i will use this inside the routing rule like i did for HL7 messages. 

i have tried MUCH prefix like "ASTM" "X12" "ESI.X12" ..... I only got errors like << PROPERTY DOES NOT EXIST >> 

Can someone tell me what i'm doing wrong ?

Thanks.

Thomas.

1 Comment
Discussão (1)1
Entre ou crie uma conta para continuar
Artigo
· Set. 17, 2024 5min de leitura

FHIR Object Modelを使ったInteroperability開発

開発者の皆さん、こんにちは。

突然ですが、2024年6月25日に開発者向けセミナー「FHIR 新機能のご紹介~2024.1~」が開催されました。
ご視聴になられた方も多数いらっしゃると思います。
まだご視聴になられていない方は是非一度、ご覧になってみてください。
YouTubeリンク

さて、こちらのセミナーにおいてご紹介された、IRIS for Health 2024.1からの新機能「FHIR Object Model」を用いて、リポジトリタイプのInteroperability開発の具体的なサンプルを作成してみました。
自身の備忘のため、すぐ開発環境を構築できるよう、コンテナ環境かつGitHubの公開もしております。
利用方法は、GitHub内のREADMEを参照ください。
GitHubリンク

目次

  1. FHIR Object Modelとは?

  2. メリット・デメリットを深堀り

  3. GitHub公開ソースについて

  4. 所感


1. FHIR Object Modelとは?


まずはFHIR Object Modelとはなにか、簡単に説明します。
FHIR Object Modelとは、FHIRリソースをオブジェクトモデル化したクラス群です。
IRIS for HealthでFHIR開発に多く携わっている方は、あれ?と思うわけです。
既に公開中のJSONテンプレートエンジンとなにが違うの?メリット・デメリットは?書き替えた方がいいの?
だいぶ主観が入りますが、JSONテンプレートエンジンとの比較をしてみたいと思います。

 

1.1. JSONテンプレートエンジンとなにが違う?


JSONテンプレートエンジン
こちらは、テンプレートクラスに記載されたテンプレートを元に、プロパティやパラメータ値を設定してJSONデータを出力します。
一方、FHIR Object Modelは、FHIRの全リソース構造を網羅したクラスを元に、プロパティを設定してFHIRオブジェクトに変換し、操作・編集が容易なクラスライブラリです。より詳細を知りたい方は、冒頭のリンクのYouTube動画を見ていただくと理解が深まると思います。


1.2. メリット・デメリットは?

  • メリット
  1. 自身でなにも用意しなくていい!ゼロベースで(IRIS for Healthをインストールさえしてあれば)使える
  2. オフィシャルのためIDEのサポートが充実
  3. DynamicAbstractObjectとの相互変換メソッド
  • デメリット
  1. 入れ子になったオブジェクトの操作は慣れが必要
  2. カスタムプロファイルに対応したモデルクラスがない
  3. 日本語ベースのドキュメントがほぼない

 

1.3. 書き替えた方がいいの?

 

個人的な意見は NO です。なぜならば、FHIR Object ModelはあくまでFHIR開発のサポートを行うためのツールであり、既に実装済みのコードがあるのであれば、書き替えるほどの強力なインパクトはありません。

 

2. メリット・デメリットを深堀り

  • メリット
  1. 自身でなにも用意しなくていい、という真意は、JSONテンプレートエンジンを利用しようとすると、どうしても自身でテンプレートクラスを作成しなくてはいけない作業が発生します。JSONテンプレートエンジンは、用意されているリソースの数に限りがあるのと、元々退院時サマリーのFHIRモデルをベースにしたテンプレートのためです。一方、FHIR Object Modelは、現状R4ベースという制限はあるものの、リソース定義がすべてクラス化されており、使い方さえわかればすぐ開発に取り掛かれます。
  2. IDEのサポートが充実しているのは、自動入力補完機能(オートコンプリート)が利用できるのと各メソッド、各プロパティにDescriptionがちゃんと(英語ですが)ついていることに尽きると思います。
  3. セミナー内の絵を拝借しますが、文字列、ダイナミックオブジェクト、FHIR Modelオブジェクトは、各クラスごとに用意されているメソッドで相互に変換でき、利用の幅が広がります。

 

  • デメリット
  1. IncludeXXXX() と MakeEntry()、そして add() する順番などが最初混乱しました。慣れてしまえば問題はないかと。
  2. カスタムプロファイルに対応したモデルクラスがないのは惜しいです。今後のリリースに期待いたします。
  3. まだ新しい機能なので、使い方や応用、実務向けサンプルなどが少ないです。だからこそ本記事を書いております。少しでもご参考になれば幸いです。


3. GitHub公開ソースについて


リポジトリタイプのInteroperabilityをコードベースで作成しました。
環境は、コンテナで動作するIRIS for Health Community 2024.1です。
インプットデータはCSVファイルで、レコードマップを定義しています。

  • Patientリソースを作成するためのPatient.csv
  • Observationリソースを作成するためのBodyMeasurement.csv

の2つを用意しており、どちらのリソースもサンプルのCSVを取り込むと常にBundleリソースに含めてtype=transactionでPOSTする形式です。

set bundle = ##class(HS.FHIRModel.R4.Bundle).%New()
set bundle.type = "transaction"
do bundle.IncludeEntry()
// ここまでは初回(bundle.entryに初めてaddするとき)のみ実行
set entry = bundle.entry.MakeEntry()
set entry.fullUrl = "urn:uuid:"_$ZCONVERT($SYSTEM.Util.CreateGUID(),"L")
do entry.IncludeResource()
// resource = HS.FHIRModel.FHIRClassSuper(HS.FHIRModel.R4.Patientなど)
set entry.resource = resource
do entry.IncludeRequest()
set entry.request.method = "POST"
set entry.request.url = resource.resourceType
do bundle.entry.add(entry)


とはいえ、Patientリソースのほうは「identifier.system|identifier.value」の条件で、存在すればPOSTしないifNoneExistプロパティを追加していますので、同じ患者IDのPatientリソースは作成されないようにしています。

// GitHubソース上では、先述のコードサンプルの bundle.entry.add() の前に入れ込んでいます
set:resource.resourceType="Patient" entry.request.ifNoneExist = "identifier=urn:oid:1.2.392.100495.20.3.51.11234567890|"_resource.identifier.get(0).get("value")


概要図はコチラです。

 

4. 所感


新機能!と思って飛びついてみましたが、IRIS経験者であればさほど苦も無く利用できると思います。
オフィシャルであることも強みで、今後の拡張やサポートにも期待しております。
GitHubのソースについて、なにかご質問あればコメントください。わかる範囲でご回答いたします。

Discussão (0)1
Entre ou crie uma conta para continuar