edifact.lua
Verified
Added by iNTERFACEWARE
Convert EDI messages to HL7 format so you can process them like an HL7 message (and convert them back to EDI afterwards)
Source Code
------------------------------------------------------------------ -- -- -- Utilities for EDIFACT Messages -- -- -- -- Copyright (c) 2012 iNTERFACEWARE Inc. All Rights Reserved. -- -- -- ------------------------------------------------------------------ local edifact = {} -- Define the header patterns in one place. local DEL = '([^%w ])' -- A delimiter. local UNA = '^UNA'..DEL:rep(3)..'(%W)(%W)'..DEL local MSH = '^MSH'..DEL:rep(5)..'%1' -- HL7 -- Some functions take a EDIFACT header as an -- argument; this is used when one is not given. local DefaultHeader = "UNA:+.?*'" -- Convert EDIFACT to HL7 with standard EDIFACT -- delimiters, HL7 escapes but no MSH header. -- function edifact.toHl7(Data) -- These are the delimiters we want. These will -- replace the input delimiters in the same order. local Output = { '^', '|', '.', '', '~', '\r' } local Escape = {'\\S\\', '\\F\\', '.', '\\E\\', '\\R\\', '\\X0D\\'} local Header = 'MSH|^~\\&|||||||EDIFACT\r' -- These are the delimiters in the message. local Input = { select(3, Data:find(UNA)) } if #Input == 0 then -- Panic! error('No UNA segment found.', 2) end -- We start with a simple map from the input -- delimiters to what we want for output. local BasicMap = {} for I,Get in ipairs(Input) do local Want = Output[I] Escape[Want] = Escape[I] BasicMap[Get] = Want end -- We expand this map to include checks for -- output delimiters in the input, and create -- a pattern to match all special characters. local Map, Pattern = { ['&']='\\T\\' }, '[%&' for Get,Want in pairs(BasicMap) do Map[Get] = Want Pattern = Pattern..'%'..Get -- Any output delimiters found in the -- input must be escaped in the output. if not BasicMap[Want] then Map[Want] = Escape[Want] Pattern = Pattern..'%'..Want end end -- If the input contains a release character, -- we expand the map and pattern further to -- handle escaped delimiters in the input. local Release = Input[4] if Release ~= ' ' then -- If a release character occurs before -- a non-delimiter, we leave it as-is. Map[Release] = Escape[Release] or Release -- Otherwise, we replace the pair with the -- second delimiter, escaped if necessary. Pattern = '%'..Release..'?'..Pattern BasicMap, Map = Map, {} for Get,Want in pairs(BasicMap) do Map[Get] = Want Map[Release..Get] = Escape[Get] or Get end end Map[' '] = nil Pattern = Pattern:gsub('%% ','') .. ']' local Out = Data:sub(10):gsub(Pattern, Map) return Header..Out end -- Convert HL7 formatted EDIFACT to real EDIFACT -- with the removal of HL7 escapes and replace -- the MSH header with an EDIFACT UNA header. -- function edifact.fromHl7(Data, NewHeader) local Dec, Seg = '.', '\r' local Ok,_,Fld,Com,Rep,Esc,Sub = Data:find(MSH) assert(Ok, 'Invalid/missing MSH segment.') Data = Data:gsub('MSH.-\r','') local Header = table.concat{ 'UNA',Com,Fld,Dec,Esc,Rep,Seg} local Escape = { ['\\'] = '\\', -- Special in HL7 only. [Com] = Esc..Com, [Fld] = Esc..Fld, [Esc] = Esc..Esc, [Seg] = Esc..Seg, [Rep] = (Rep ~= ' ') and Esc..Rep } -- First we escape every occurance of the -- release character in the input. local Out = Data if #Esc > 0 then -- Assuming we need to. Data:gsub('%'..Esc, Escape[Esc]) end -- Then we replace all HL7 escapes with -- EDIFACT escapes or regular characters. Out = Out:gsub('(\\%u%x?%x?\\)', setmetatable({ ['\\S\\'] = Escape[Com], ['\\F\\'] = Escape[Fld], ['\\E\\'] = Escape['\\'], ['\\R\\'] = Escape[Rep], ['\\T\\'] = Sub, -- Not special. -- ['\\X27\\'] = Escape[Seg], }, { -- This handles other \X..\ escapes -- which could be present in HL7. __index = function(self, s) local Out = s:gsub('\\X(%x%x)\\', function(hex) local i = tonumber(hex,16) return string.char(i) end) Out = Escape[Out] or Out self[s] = Out -- Memoize. return Out end })) Out = edifact.clean(Header..Out, NewHeader) return Out end -- Replace the delimiters of an EDIFACT message -- with those in the header provided or use the -- default EDIFACT delimiters. -- function edifact.clean(Data, Header) Header = Header or DefaultHeader local Input = { select(3, Data :find(UNA)) } local Output = { select(3, Header:find(UNA..'$')) } local InpRelease, OutRelease = Input[4], Output[4] if not InpRelease then error('Bad UNA header in message.', 2) end if not OutRelease then error('Invalid output header.', 2) end local Escape, Map, Pattern = {}, {}, '[' if OutRelease ~= ' ' then for _,Want in ipairs(Output) do Escape[Want] = OutRelease..Want Map[Want] = OutRelease..Want Pattern = Pattern..'%'..Want end end for I,Get in ipairs(Input) do local Want = Output[I] Map[Get] = Want Pattern = Pattern..'%'..Get end if InpRelease ~= ' ' then Pattern = '%'..InpRelease..'?'..Pattern for I,Get in ipairs(Input) do Map[InpRelease..Get] = Escape[Get] or Get end end Map[' '] = nil Pattern = Pattern:gsub('%% ','') .. ']' local Out = Data:sub(10):gsub(Pattern,Map) return Header..Out end return edifact
Description
Convert EDI messages to HL7 format so you can process them like an HL7 message (and convert them back to EDI afterwards)
Attachments
Usage Details
EDIFACT and HL7 are very similar. The main difference is how delimiters are escaped when they occur in a message. For instance, in the following EDIFACT snippet, the question-mark (?) is used to escape delimiters, or “release” them in EDIFACT parlance.
This module allows you to convert messages back an forth between EDI and HL7. This means you can convert an incoming EDI message to HL7, then process it as an HL7 message (hl7.parse{}, map fields etc), then convert it back to EDI and forward it.
How to use edifact.lua:
- Use a Filter or To Translator component
- Create the edifact module and paste in the code
Note: You can also load the attached project edifact.zip - Add some sample HL7 messages from SampleData.txt
Note: The project already contains the sample data - Load sample EDI messages if you have some (useful but not required)
- Convert HL7 to EDI with
edifact.fromHl7()
, then convert it back with edifact.toHl7() - Play with the code and compare annotations to see how it works
Here is some sample code for main()
:
local edifact = require 'edifact' function main(Data) local edi = edifact.fromHl7(Data) -- convert to EDI local hl7 = edifact.toHl7(edi) -- convert back to HL7 trace(edi) trace(hl7) end
More Information