› Clovertech Forums › Read Only Archives › Cloverleaf › Tcl Library › rebuild IN1 segment order based on IN1.22 replacing IN1.1
Input:
IN1.1 = 1
Just curious which vendor you are doing this for, especially if it is for AuditLogix.
I did not get to the nitty gritty yet with some many projects to work on, but think I know enough to do the resequencing especially since Jim Kosloskey (Mr Iteration) is on our team if I need to call on him.
I did take a quick look and found out the IN# segments are groups including IN1, IN2, IN3 so keep that in mind when you reorder them you likely will be dealing with reordering the entire group and not just a single segment.
At least I will have to deal with that.
Here is a more visual look at the grouping I’m talking about as it is defined in the variant
IN1
[ IN2 ]
[ IN3 ]
}
I also noticed my problem includes a challenge of a redundant nature where my ascending codes are sometimes the same, for example:
IN1-1 = 1; IN1-22 = 3
IN1-1 = 2; IN1-22 = 2
IN1-1 = 3; IN1-22 = 2
IN1-1 = 4; IN1-22 = 1
You may also want to bring this up for discusion as to how to handle this situation even if they say it doesn’t happen becuase they told me it doesn’t happen hear and I found out otherwise, so best to handle the reality of it.
One trick that I will be looking to exploit is to do math on a basis counter you are iterating over is to reference it as $%g1 for example or something like that.
If all else fails I can write an xlt proc to use xpm to do just about anything I would imagine.
With so many projects to work on you may not want to wait on me to get started or better yet you figure it out and give it to me.
Here is a xlt proc ( xlt_create_NTE_from_OBX7 ) that illustrates how I used xmp for another integration I wrote to create extra NTE segment(s) which might have concepts useful to this integration:
# Begin Module Header ==========================================================
#
#——
# Name:
#——
#
# xlt_create_NTE_from_OBX7.tcl
#
#———
# Purpose:
#———
#
# If any of these conditions are true:
#
# OBX 7 contains the character “<"
# OBX 7 contains the character ">”
#
# then delete the OBX 7 field
# and create the next NTE segment
# with the observation results in OBX 7
# for example, if OBX 7 = |<0.25| then create:
#
# NTE|01||<0.25
#
#--------
# Inputs:
#--------
#
# xlateInVals 0 = OBX 7 (observation results)
# xlateInVals 1 = turns on debugging if it exists
#
#---------
# Outputs:
#---------
#
# xlateOutVals 0 = OBX 7 (observation results)
#
#-------
# Notes:
#-------
#
# PICIS requires that OBX 7 (observation results) contains a range of numbers
# with a minimum and maximum value like |22-33| or |-33 - -22|; however,
# our lab system might send ranges like |<0.25| or |>-44| which PICIS can’t handle
#
#———
# History:
#———
#
# 2001.04.04 Russ Ross
# – wrote initial version
#
# End Module Header ============================================================
proc xlt_create_NTE_from_OBX7 {} {
upvar xlateId xlateId
xlateInList xlateInList
xlateInTypes xlateInTypes
xlateInVals xlateInVals
xlateOutList xlateOutList
xlateOutTypes xlateOutTypes
xlateOutVals xlateOutVals
#————————————————–
# save the current datum list
# that will need to be reset when this proc is done
#————————————————–
set datum_list [datlist]
#————————————————–
# initialize the variables that this proc will need
#————————————————–
set module “xlt_create_NTE_from_OBX7”
set OBX7_observation_results [lindex $xlateInVals 0]
set dh_g1 [xpmfetch $xlateId @g1]
set dh_g2 [xpmfetch $xlateId @g2]
set dh_g3 [xpmfetch $xlateId @g3]
set dh_s1 [xpmfetch $xlateId @s1]
set g1 [datget $dh_g1 VALUE]
set g2 [datget $dh_g2 VALUE]
set g3 [datget $dh_g3 VALUE]
set s1 [datget $dh_s1 VALUE]
#——————————————–
# see if any of these conditions are true:
#
# OBX 7 contains the character “<"
# OBX 7 contains the character ">”
#——————————————–
if { [regexp (<+) "$OBX7_observation_results"] || [regexp (>+) “$OBX7_observation_results”] } {
#——————————————————————
# create the next NTE segment with the observation results in OBX 7
#——————————————————————
set next_s1 [incr s1]
set NTE_counter [incr s1]
xpmstore $xlateId 1($g1).1($g2).1($g3).NTE($next_s1).#1 c $NTE_counter
xpmstore $xlateId 1($g1).1($g2).1($g3).NTE($next_s1).#3 c “Normal Range $OBX7_observation_results”
#———————–
# delete the OBX 7 field
#———————–
set xlateOutVals [list “”]
#————————————
# see if debugging has been turned on
#————————————
if { [llength $xlateInVals] > 1 } {
set MSH_date_time [datget [xpmfetch $xlateId 0(0).MSH(0).#7 ] VALUE]
set MSH_seq [datget [xpmfetch $xlateId 0(0).MSH(0).#10] VALUE]
set PID_mrn [datget [xpmfetch $xlateId 1($g1).0(0).PID(0).#3] VALUE]
set PID_last_name [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[0]}] VALUE]
set PID_first_name [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[1]}] VALUE]
set PID_middle_name [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[2]}] VALUE]
puts “($module): =========================”
puts “($module): MSH_date_time ($MSH_date_time)”
puts “($module): MSH_seq ($MSH_seq)”
puts “($module): PID_mrn ($PID_mrn)”
puts “($module): PID_first_name ($PID_first_name)”
puts “($module): PID_middle_name ($PID_middle_name)”
puts “($module): PID_last_name ($PID_last_name)”
puts “($module): OBX7_observation_results ($OBX7_observation_results)”
puts “($module): =========================”
}
}
#——————————————————————-
# reset the datum list back to what is was when this proc was called
#——————————————————————-
hcidatlistreset $datum_list
}
Below is a screen shot showing the xlate that calls this proc.
Russ Ross
RussRoss318@gmail.com
https://usspvlclovertch2.infor.com/viewtopic.php?t=2091https://usspvlclovertch2.infor.com/viewtopic.php?t=2091
Russ Ross
RussRoss318@gmail.com
You could just simply use IF statements (in the Xlate) within the iteration of the insurance, and based on the value in IN1:22 map to the respective outbound repetition of the IN1. i.e. see the attached translation snippet (which assumes up to 4 insurances), and I used simple PATHCOPY’s for illustration purposes.
FYI – change the extension back to .xlt – I just changed it to .xls to allow it to upload.
Hope this helps.
Jim Cobane
Henry Ford Health
run {
# ‘run’ mode always has a MSGID; fetch and process it
keylget args MSGID mh
set msg [msgget $mh]
set segs [split $msg “r”]
set pipe [string range $msg 3 3]
set in1segs [lsearch -all -inline -regexp $segs {^IN1}]
set in1nums [lsearch -all -regexp $segs {^IN1}]
# create a list for sorting that has in1 field 22 followed
# by the in1 segment number
set in1sortlist {}
for { set num 0 } { $num < [llength $in1nums] } { incr num } {
set in1 [lindex $in1segs $num]
set in1_22 [lindex [split $in1 $pipe] 22]
lappend in1sortlist [list $in1_22 $num]
}
set in1sortlist [lsort -integer -index 0 $in1sortlist]
# put the segments back into the message in the order
# specified by the sorted list
for { set num 0 } { $num < [llength $in1nums] } { incr num } {
set num2 [lindex [lindex $in1sortlist $num] 1]
set in1num [lindex $in1nums $num]
set segs [lreplace $segs $in1num $in1num
[lindex $in1segs $num2]]
}
set msg [join $segs r]
msgset $mh $msg
lappend dispList "CONTINUE $mh"
}
That puts the IN1 in the correct order, but you will need some additional coding to handle the possible IN2 and IN3 segments that may accompany them.
Tom
I looked at your downlaodable XLT and was able to use your outlined method to reorder the IN1 groups as needed quite nicely.
Since I will never have more than 4 IN1 groups I don’t have to have logic to handle infinite IN1 groups.
Now all I will need is to find out how they want me to deal with duplicate priorities.
You may have noticed I added a check for a null priority since that comes across sometimes in my case.
Here is the test xlate I have so far which is almost identical to yours with a bit of exapansion to copy the entire IN1 group:
prologue
xlt_infile: hl7 2.3 global_super_adt ADT_A01
who: RRoss
date: September 13, 2007 7:48:58 PM CDT
xlt_outfile: hl7 2.3 global_super_adt ADT_001
type: xlt
version: 5.0
end_prologue
{ { OP ITERATE }
{ BASIS 3(0).0 }
{ VAR %g1 }
{ TYPE group }
{ BODY {
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
{ THENBODY {
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] eq =1} }
{ THENBODY {
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(0).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(0).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(0).IN3 }
}
}}
{ ELSEBODY {
}}
}
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] eq =2} }
{ THENBODY {
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(1).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(1).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(1).IN3 }
}
}}
{ ELSEBODY {
}}
}
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] eq =3} }
{ THENBODY {
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(2).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(2).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(2).IN3 }
}
}}
{ ELSEBODY {
}}
}
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] eq =4} }
{ THENBODY {
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(3).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(3).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(3).IN3 }
}
}}
{ ELSEBODY {
}}
}
}}
{ ELSEBODY {
}}
}
}}
}
Attached is a screen shot of the Xlate to help illustrate for those that may not want to go through the hassel of improting the xlate into cloverleaf and launching the IDE to get the drift.
Russ Ross
RussRoss318@gmail.com
Thanks to Jim Kosloskey for telling me exactly how to use the $%g2 notation which I was aware of for a long time but until I used it today kept putting off understanding it enough to benifit.
As you will see this creates an amazingly simple solution.
The reason I did a math subtract was the IN1-22 codes start with 1 and the %g2 pathing needs to start with zero.
Here is the Xlate:
prologue
xlt_infile: hl7 2.3 global_super_adt ADT_A01
who: RRoss
date: September 14, 2007 3:08:11 PM CDT
xlt_outfile: hl7 2.3 global_super_adt ADT_001
type: xlt
version: 5.0
end_prologue
{ { OP ITERATE }
{ BASIS 3(0).0 }
{ VAR %g1 }
{ TYPE group }
{ BODY {
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
{ THENBODY {
{ { OP SUB }
{ ERR 0 }
{ IN {{3(0).0(%g1).IN1.#22.[0]} =1} }
{ OUT {{$%g2}} }
{ FUNCTION SUB }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(%g2).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(%g2).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(%g2).IN3 }
}
}}
{ ELSEBODY {
}}
}
}}
}
Below is the screen shot of this xlate to help see how %g2 gets set and used which is the key concept of this post.
Russ Ross
RussRoss318@gmail.com
Now the real fun begins.
I just finished a discussion about how to handle duplicate priority codes when doing the IN1 regrouping.
Here we believe in using the Xlate if possible before resorting to TCL code to give a level one person a better chance of understanding and supporting the integration.
Obviously I could resort to TCL and take care of my extra conditions described below.
Attached is the email I sent that describes an overview of the logic to handle duplicate priority codes that I will be working towards for those that want to follow along.
If anyone has ideas on how to use the xlate to approach this problem then I’m listening and thanks.
My first thought is it will probably require more than one iteration pass over the IN1 groups (ex: the first pass might be to determine if there are any duplicates).
Russ Ross
RussRoss318@gmail.com
With that in mind I also observed that the IN1 groups on the output do not have to be sequential and any empty IN1 groups will get collapsed by cloverleaf on the way out since the IN1 group is optional.
This observation allowed for a rather clever solution which I will proceed to share.
Previously I had used the priority code in IN1-22 to set the output group %g2 but when I had a duplicate priority they both used the same value for %g2 and one overwrote the other.
So what I did was to use a simple hash table technique by multipling the IN1-22 priority code by 2 which creates a one group gap between each IN1 group on the outbound xlate.
This leaves room for the case of a duplicate which is handled by subracting one from $%g2 when I incurr IN1-2 = M95.
Turns out to be very compact and only requires one pass to sort and handle duplicates; daddy would be proud.
Here is the relevant part of the xlate:
prologue
xlt_infile: hl7 2.3 global_super_adt ADT_A01
who: RRoss
date: September 17, 2007 7:07:35 PM CDT
xlt_outfile: hl7 2.3 global_super_adt ADT_001
type: xlt
version: 5.0
end_prologue
{ { OP ITERATE }
{ BASIS 3(0).0 }
{ VAR %g1 }
{ TYPE group }
{ BODY {
{ { OP IF }
{ ERR 0 }
{ COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
{ THENBODY {
{ { OP MUL }
{ ERR 0 }
{ IN {{3(0).0(%g1).IN1.#22.[0]} =2} }
{ OUT {{$%g2}} }
{ FUNCTION MUL }
}
{ { OP IF }
{ ERR 0 }
{ COND { 3(0).0(%g1).IN1.#2.[0] eq =M95} }
{ THENBODY {
{ { OP SUB }
{ ERR 0 }
{ IN {{$%g2} =1} }
{ OUT {{$%g2}} }
{ FUNCTION SUB }
}
}}
{ ELSEBODY {
}}
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN1 }
{ OUT 3(0).0(%g2).IN1 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN2 }
{ OUT 3(0).0(%g2).IN2 }
}
{ { OP PATHCOPY }
{ ERR 0 }
{ IN 3(0).0(%g1).IN3 }
{ OUT 3(0).0(%g2).IN3 }
}
}}
{ ELSEBODY {
}}
}
}}
}
Russ Ross
RussRoss318@gmail.com
{ { OP ITERATE }
{ BASIS 1(0).0(%g1) }
{ VAR %g1 }
{ TYPE group }
{ BODY {
{ { OP COMMENT }
{ COMMENT {TODO: Insert new actions here} }
}
{ { OP IF }
{ ERR 0 }
{ COND { 1(0).0(%g1).IN1.00447.[0] eq =1} }
{ THENBODY {
{ { OP COMMENT }
{ COMMENT {TODO: Insert new actions here} }
}
{ { OP COPY }
{ ERR 0 }
{ IN @null }
{ OUT 3(0).0(0).IN1.00368 }
}
{ { OP COPY }
{ ERR 0 }
{ IN =01 }
{ OUT 3(0).0(0).IN1.00426 }
}
{ { OP COPY }
{ ERR 0 }
{ IN 1(0).0(%g1).IN1.00428 }
{ OUT 3(0).0(0).IN1.00428(0) }