How to approach X12 parsing

This article helps to begin with writing X12 parsing interface. All comments and explanations in the code snippet below.

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 


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 

function main()  

   local function readMyFile(fn)
      local f = assert(, 'rb'))
      local d = f:read('*a')

      return d

   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
   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()


         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 

         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 and process content.

         Hypothetical next component can do, for example, 271 construction (see 
         function x12.message{} at
         as Transaction Sets get processed, or to write parsed data to database
         (see selected database related parts of example on page , 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()


function foo(n)   
   return n["Position 010"].Grp010ABCD[1].Loop2000A.Loop2100A.NM1[3]:nodeValue()

function foo2(TS)
   --[[ Please see selected database related parts from example of writing to 
   database on page
   return true

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.


Leave a Reply