Introduction
How to approach X12 parsing: This article helps to begin with writing X12 parsing interface. All comments and explanations in the code snippet below.
Task [top]
How to approach X12 parsing.
Implementation [top]
Please pay attention to use Library VMD file respective to version of X12 you are using in real life, i.e. 4010 or 5010.
Different examples in our Wiki make mixed use of these two standards, but in real life interface strictly one of the two Standards must be followed.
--[[ Prior to parsing, create a 'copy' of X12 Library VMD file. Remove from 'copy' all Transactions you aren't going to use with this specific interface. Add to 'copy' Segment Grammar the Functional Groups and the Interchange Envelope segments. See example in 270v3.vmd file, where hierarchy is defined as following: *InteractionEnvelope **FunctionalGroup ***TransactionSet In shorthand notation it could be expressed as ISA [{GS [{ST ... SE}] GE}] IEA The v3 in vmd file name has nothing to do with versions of X12 or HL7. Simply two earlier versions of this file were insatisfactory. ]] function main() local function readMyFile(fn) local f = assert(io.open(fn, 'rb')) local d = f:read('*a') f:close() return d end local Data = readMyFile('/Users/levblum/270BlueCrossEdited.edi') --[[ Optionally, Interchange delimiters can be normalized here, e.g. Data = Data:gsub('r','~') Above example replaces <CR> Segments Terminator with tilde. In your specific data, the character to replace will be the one on 106th place in ISA segment. So that example can be enhanced to be Data = Data:gsub(Data:sub(106,106),'~'). Translator's X12 module expects to find standard Interchange delimiters in a message. If needed, delimiters can be reversed to original values after processing by Translator got completed. ]] local In,Name,Warnings = x12.parse{ vmd = 'example/270v3.vmd', data = Data} --[[ Optionally, some sanity tests for validation of data can take place here. Please see TA1 acknowledgement example in Wiki at http://wiki.interfaceware.com/388.html This example shows TA1 for 270/271 "HealthCare Eligibility Benefit Inquiry and Response" scenario, as per 004010X092 ]] local TS --[[ Now substract every single Transaction Set to be processed as single Transaction Set. ]] for i=1,In.InterchangeEnvelope.IEA[1]:nodeValue() do for j=1,In.InterchangeEnvelope.FunctionalGroup[i].GE[1]:nodeValue() do TS = In.InterchangeEnvelope.FunctionalGroup[i].TransactionSet[j] --[[ To push it into Iguana's queue, to be processed by next channels component, call function queue.push{}, e.g. queue.push{data = tostring(TS):gsub('r','~')} Note the tilde placed back as Segment Terminator. ]] --[[ To process otherwise, call some other function, e.g. function foo() foo(TS) or another example local Success, s = pcall(foo2,TS) ]] --[[ The X12 Interchange Envelope may contain huge number of Transacion Sets, thus it only makes sense to push individual Transaction Sets into Iguana's queue one by one to be processed by next channels component. This, instead of processing them by local function in this channels component. This recommended approach will speed up over all processing speed of given interface. ]] --[[ JSON to the resque Whenever next Transaction Set is processed by next channels component, we often wish to know which Functional Group it comes from, and which Interchange Envelope, etc... To pass this information along with Transaction Set content, we can combine variable TS with values from GS/GE ans ISA/IEA segments into JSON object. This JSON object get pushed into Iguana's queue. Then next channels component will decompose the object as shown in example on page http://wiki.interfaceware.com/1337.html and process content. Hypothetical next component can do, for example, 271 construction (see function x12.message{} at http://wiki.interfaceware.com/425.html#message) as Transaction Sets get processed, or to write parsed data to database (see selected database related parts of example on page http://wiki.interfaceware.com/1456.html), or so... For example: local Messages = {} Messages[1] = tostring(TS):gsub('r','~') Messages[2] = In.InterchangeEnvelope.FunctionalGroup[i].GE[2]:nodeValue() Messages[3] = In.InterchangeEnvelope.IEA[2]:nodeValue() queue.push{data=json.serialize{data=Messages}} ]] end end end function foo(n) return n["Position 010"].Grp010ABCD[1].Loop2000A.Loop2100A.NM1[3]:nodeValue() end function foo2(TS) --[[ Please see selected database related parts from example of writing to database on page http://wiki.interfaceware.com/1456.html ]] return true end
Attached Translator project has to be imported in Source component, to take advantage of allowed multiple calls to function queue.push{}.
Please note that in future versions of Iguana, multiple calls to queue.push{} will be allowed in Filter component as well.
270BlueCrossEdited.edi
X12_parsing_example_Source.zip
More information [top]
- Our X12 section
- Repository Code: