The zsegment module
Contents
We’re going to create a new shared module called zsegment. From the project files pane of the Translator click on Add…

This dialog will come up. Enter zsegment in the Create a new module textbox:

Then click on the Create button.
The new module will be appear in the Project Files pane:

Click on zsegment and then copy-paste the following code into the module:
zsegment = {}
local function trace(a,b,c,d) return end
function zsegment.extractZSegment(Msg)
local Segments = Msg:split('\r')
local ZSegments = {}
for i = 1, #Segments do
if Segments[i]:sub(1,1) == 'Z' then
trace('Found '..Segments[i])
ZSegments[i] = Segments[i]
end
end
return ZSegments
end
function zsegment.copyZSegments(Orig, Copy)
-- enforce correct return character
Copy = Copy:gsub('\r?\n','\r')
Orig = Orig:gsub('\r?\n','\r')
-- and strip return(s) from end of string
-- '$' anchors matching to end of string
Copy = Copy:gsub('\r+$','')
local ZSegments = zsegment.extractZSegment(Orig)
local SegmentList = Copy:split('\r')
trace(SegmentList)
for K,V in pairs(ZSegments) do
table.insert(SegmentList, V)
end
trace(SegmentList)
local Result = ''
for i = 1, #SegmentList do
Result = Result..SegmentList[i]..'\r'
end
return Result
end
The beauty of the Translator is that:
- One can implement sophisticated logic
- Other people in your team can easily see what you have done
Do take the time to step through and look through the annotations of the zsegment module to understand it. It’s simple. This is how it works:
- The
extractZSegment()function:- Slices the segments apart by splitting on the carriage return ‘\r’ character.
- Creates an array of those segments which start with Z, i.e., Z-segments.
- The main
copyZSegments()routine takes the HL7 message without Z-segments and does the folowing:- Ensures the correct return character is used.
- Removes any returns from the end of the message.
- Slices it into segments also by splitting on the \r character.
- Then appends the Z-segments.
The Translator makes writing reusable modules like this easy. It’s one of the many things that makes Iguana so fun and productive.
Now go back to the main module and insert two require statements at the top:
require 'split' require 'zsegment'
Then add these lines to the main module:

Notice how we still have our error. If we look at the two extra trace lines we added earlier in the ‘Escaped Text’ mode we immediately see the culprit: there is a trailing carriage return in the copied data.

The new version of the message has a trailing \r. We can trim that \r using a helpful string extension we can write:
function string.StripLastReturns(S)
-- strip return(s) "\r" & "\n" from the end of a string
local i = #S
while S:byte(i) == 10 or S:byte(i) == 13 do
i = i - 1
end
return S:sub(1,i)
end
That means we can apply to any string and it will strip one or more \r or \n off the end.:StripLastReturns()
This function uses
- # operator – returns the number of characters in the string
byte(N)– returns the byte at the Nth place.– returns the substring at the indexes given.sub(Start, End)
These are part of the standard Lua string library.
So we make things work by altering the code to the following:

Notice how I used Data:StripLastReturns() as well to ensure there are no unwanted returns on the Data or the Copy.
You can really start to appreciate the visibility and power the Translator environment gives.
If you need to ensure your code is up-to-date then copy-paste this in:
require 'split'
require 'zsegment'
local function trace(a,b,c,d) return end
function main(Data)
local Orig = hl7.parse {vmd = 'transform.vmd', data = Data}
local Out = hl7.message{vmd = 'transform.vmd', name = Orig:nodeName()}
Out:mapTree(Orig)
local Copy = zsegment.copyZSegments(Data, Out:S())
CheckTransform(Data, Copy:StripLastReturns())
Out.MSH[3][1] = 'Acme'
Out.MSH[4][1] = 'Lab'
trace(Out)
local DataOut = Out:S()
DataOut = zsegment.copyZSegments(Data, DataOut)
DataOut = DataOut:StripLastReturns()
trace(DataOut)
queue.push{data = DataOut}
end
function CheckTransform(Orig, Copy)
if Orig ~= Copy then
trace(Orig)
trace(Copy)
error('Copy of HL7 message does not match the original')
end
end
function string.StripLastReturns(S)
-- strip return(s) "\r" & "\n" from the end of a string
local i = #S
while S:byte(i) == 10 or S:byte(i) == 13 do
i = i - 1
end
return S:sub(1,i)
end
We still have one major difference to overcome with how we are handling ORM messages, but we will use that as an opportunity to show how Iguana can handle runtime errors.