Homepage › Clovertech Forums › Read Only Archives › Cloverleaf › Tcl Library › rebuild IN1 segment order based on IN1.22 replacing IN1.1
- This topic has 11 replies, 5 voices, and was last updated 17 years ago by Cesario Perez.
-
CreatorTopic
-
September 11, 2007 at 2:53 pm #49511Cesario PerezParticipant
I have been asked to rebuild an hl7 message insurance segment grouping based on IN1.22 (coordination of benefits) mapped to IN1.1 (setid) and resequence the IN1 segments based on the mapping change value. Example: Input:
IN1.1 = 1
-
CreatorTopic
-
AuthorReplies
-
-
September 11, 2007 at 9:06 pm #62263Russ RossParticipant
I have to do the same thing for a project just assigned to me for an intergration to AuditLogix. 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:
Code:# 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 -
September 11, 2007 at 9:19 pm #62264Russ RossParticipant
Here is another URL that could be useful to this integration that I will put some time into understanding as I proceed. http://clovertech.infor.com/viewtopic.php?t=2091http://clovertech.infor.com/viewtopic.php?t=2091” class=”bbcode_url”> Russ Ross
RussRoss318@gmail.com -
September 12, 2007 at 2:09 pm #62265James CobaneParticipant
Cesario, 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
-
September 12, 2007 at 5:11 pm #62266Cesario PerezParticipant
Thank you very much for the different angles. The current setup is an xlate and a outbound tps tcl which matches up an insurance code across systems. I tried inserting a map in1.22 to in1.1 with a iterate copy % variable and then execute the ins code crosswalk tcl but that xlate really clobbered the output because when the tcl executed it lost track of which in1 segment it was working with. Or say I lost control of the situation and the user needed to move forward on general testing. So I backed out of it and feel that I will be given this assignment in the near future and I will keep you posted of the results. The bottom line is I hope I can accomplish this without changing too much of the configuration which exists now. And no Russ it’s not that vendor it’s a user request. I just don’t understand how that will make an improvement but oh well. -
September 13, 2007 at 1:30 pm #62267David BarrParticipant
Here’s how to handle the problem in a TPS proc: Code: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" } -
September 13, 2007 at 2:29 pm #62268Tom RiouxParticipant
David, 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
-
September 14, 2007 at 12:07 am #62269Russ RossParticipant
Thanks James Cobane: 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:
Code: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 -
September 14, 2007 at 7:42 pm #62270Russ RossParticipant
I’ve always wanted to use and understand the notation $%g2 so I took my previous xlate and applied that $%g2 notation to make a sleeker version to accomplish the same logic of regrouping the IN1 groups as desired. 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:
Code: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 -
September 14, 2007 at 9:16 pm #62271Russ RossParticipant
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 -
September 17, 2007 at 11:10 pm #62272Russ RossParticipant
After more discussion it turns out that if I have a duplicate priority then if IN1-2.1 = M95 that one goes first. 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:
Code: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 -
September 18, 2007 at 8:51 pm #62273Cesario PerezParticipant
I have it working based on your suggestions in xlate. My previous work in xlate and tcl failed because I did not take it further. But by others help nd your ideas I’m home. I hard code the output mapping (0,1,2) for in22 = 1,2,3. I am assuming there will be no duplicate in1.22 and no more than 3 in1 segments in the message. Thanks again and here is my code which is just like your examples, I left out bulk which included all in1,in2 and in3 fields. { { 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) }
-
-
AuthorReplies
- The forum ‘Tcl Library’ is closed to new topics and replies.