The IRIS regex functionality is built on the ICU engine, which was based on (but does not rigorously adhere to) PCRE. This includes the ObjectScript $MATCH() and $LOCATE() functions as well as the %Regex.Matcher class. A web search turns up a handful of articles and posts discussing the differences between the two.

Python has a PCRE library (python-pcre) that may help if your development effort can be transitioned in whole or part to Python.

Thanks, this is useful @Nick Petrocelli! It appears that the order in which the properties are returned by iterating with Count() is sorted alphabetically. Is there any way to fetch them in the order in which they were defined in the class? I have SqlColumnNumber assigned for each of the properties, so if there's a way to fetch that keyword's value I can order them according to that. I'd prefer not to hard-code them in if possible, as the spec may change ...

Thanks!

You can select from a number of Linux vendors/versions for an AWS installation. I would recommend you select Red Hat or Ubuntu rather than Amazon Linux; InterSystems officially supports those.

In my experience Red Hat is the more stable/compatible version and is the most widely used for IRIS implementations.

You would not install Ubuntu or Red Hat "on top of" Amazon Linux; you would select the Linux flavor when creating your EC2 instance.

Because it's a method defined with the [ Internal ] keyword, which the class documentation generator excludes. That keyword means that it's not recommended for use by anyone other than InterSystems. Its behavior may change or it may go away, and you're taking a chance by implementing it in your own code.

GetSegmentAt() provides the same functionality but is documented for use by anyone. It's defined in a class (EnsLib.EDI.Segmented) that is inherited by EnsLib.HL7.Message and other virtual document classes.

I did:

Class OrdRes.VendorMDM Extends Ens.DataTransformDTL [ DependsOn = EnsLib.HL7.Message ]
{

Parameter IGNOREMISSINGSOURCE = 1;
Parameter REPORTERRORS = 1;
Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;
XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='EnsLib.HL7.Message' targetClass='EnsLib.HL7.Message' sourceDocType='2.3:ORU_R01' targetDocType='2.5:MDM_T02' create='new' language='objectscript' >
<assign value='source.{MSH}' property='target.{MSH}' action='set' />
<assign value='"MDM"' property='target.{MSH:MessageType.MessageCode}' action='set' />
<assign value='"T02"' property='target.{MSH:MessageType.TriggerEvent}' action='set' />
<assign value='"2.5"' property='target.{MSH:VersionID.VersionID}' action='set' />
<assign value='source.{MSH:DateTimeofMessage}' property='target.{EVN:2}' action='set' />
<assign value='source.{PIDgrpgrp(1).PIDgrp.PID}' property='target.{PID}' action='set' />
<assign value='source.{PIDgrpgrp(1).PIDgrp.PV1grp.PV1}' property='target.{PV1}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).ORC}' property='target.{ORCgrp(1).ORC}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBR}' property='target.{ORCgrp(1).OBR}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).NTE()}' property='target.{ORCgrp(1).NTE()}' action='set' />
<assign value='"Endoscopy Image"' property='target.{TXA:DocumentType}' action='set' />
<assign value='"AU"' property='target.{TXA:DocumentCompletionStatus}' action='set' />
<assign value='"AV"' property='target.{TXA:DocumentAvailabilityStatus}' action='set' />
<foreach property='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp()}' key='k1' >
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:SetIDOBX}' property='target.{OBXgrp(k1).OBX:SetIDOBX}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:ValueType}' property='target.{OBXgrp(k1).OBX:ValueType}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:ObservationIdentifier}' property='target.{OBXgrp(k1).OBX:ObservationIdentifier}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:ObservationSubID}' property='target.{OBXgrp(k1).OBX:ObservationSubID}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:Units.identifier}' property='target.{OBXgrp(k1).OBX:5.3}' action='set' />
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:Units.identifier}' property='target.{OBXgrp(k1).OBX:5.4}' action='set' />
<if condition='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX:SetIDOBX}' >
<true>
<code>
<![CDATA[ do source.GetFieldStreamRaw(.tStream,"PIDgrpgrp(1).ORCgrp(1).OBXgrp("_k1_").OBX:5(1).1",.tRem)
 //
 set tRem = "|PDF|||||F|"
 //
 // Store the stream to the appropriate target field
 do target.StoreFieldStreamRaw(tStream,"OBXgrp("_k1_").OBX:5(1).5",tRem)]]></code>
</true>
<false>
<assign value='source.{PIDgrpgrp(1).ORCgrp(1).OBXgrp(k1).OBX}' property='target.{OBXgrp(k1).OBX}' action='set' />
</false>
</if>
</foreach>
<assign value='source.{PID:18}' property='target.{TXA:12.3}' action='set' />
</transform>
}

}

Now, I used PDFs rather than BMPs, I'm a little OCD, so my output looks slightly different from yours. But it does work. Notice that I used the numeric syntax to reference OBX:5's components, though. There are no symbolic names for those components in HL7, but they're still recognized using the numeric syntax.

Also, I think one of the OBX:5 components should probably contain "Base64" since that's probably how OBX:5.5 is encoded.

Here's the output:

Hi Anthony,

I think the issue is that you're using GetFieldStreamRaw() against the entire OBX segment, when you should be using it against the field that contains the stream: OBX:5.1. The method can take 3 arguments, the 3rd being a variable passed by reference that contains the remainder of the current OBX segment. That variable is of type %String and can be modified to include different values for the remaining fields, and then supplied as the 3rd argument to StoreFieldStreamRaw() ... which you would use to populate OBX:5.5.

These methods are usually used in a code block, where passing a variable by reference is supported (precede it with a period). You'll need to do that with both the first and 3rd arguments in GetFieldStreamRaw().

It's also important to note that once you've used StoreFieldStreamRaw(), the target segment becomes immutable; no further changes can be made to it. That's why the remainder variable is so important as it populates the remainder of the segment at the time the stream is stored to the field.

The DTL flow would Look like this:

  1. Populate everything in the target message, up to the OBX
  2. In a Foreach over the OBX:
    1. Populate everything in the target OBX preceding OBX:5.5
    2. Execute a code block similar to the following:
// Get the stream data (no need to instantiate a stream object in advance)
do source.GetFieldStreamRaw(.tStream,"PIDgrpgrp(1).ORCgrp(1).OBXgrp("_k1_").OBX:5(1).1",.tRem)
//
// Insert code here to modify tRem to accommodate any changes needed to 
// fields after OBX:5(1).5
//
// Store the stream to the appropriate target field
do target.StoreFieldStreamRaw(tStream,"OBXgrp("_k1_").OBX:5(1).5",tRem)

Then populate any remaining segments as you normally would.