Question
· Jan 27, 2023

Account for different parsing technique in EnsLib.HL7.Service.FileService??

I have a system that is sending Line Breaks\Carriage Returns within the text of a field that is breaking the parsing of the message. Does anyone have a way to get around this?

here is what I receive... 

ZPR|29|937952|UH|Physician Assistant - Certified|Primary Privileges:  Physician Assistant|Care of simple fractures including extremity, rib and clavicle; including skeletal
immobilization||

as EnsLib.HL7.Service.FileService parses the message it puts immobilization on a new line because of the hidden line break, and the rest of the message is lost.

I tried using tr, sed, perl from a unix command line to reformat the message before it gets to Ensemble but I can't get the right combination to make sure the Line Feed is not in that field. The users of the system don't understand what I am asking of them and the vendor of the system has been no help either.

Does anyone have a way to create a custom parser that only looks for SEGMENTS to parse the message apart?

Product version: Caché 2018.1
$ZV: Cache for UNIX (IBM AIX for System Power System-64) 2018.1.3 (Build 414U) Mon Oct 28 2019 11:24:02 EDT
Discussion (5)1
Log in or sign up to continue

this might do it:

Class User.Scott 
{
ClassMethod Clean(infile, outfile) As %Status
{
  set in=##class(%Stream.FileCharacter).%New()
  do in.LinkToFile(infile)
  set out=##class(%Stream.FileCharacter).%New()
  set out.Filename=outfile
  do in.Rewind()
  while 'in.AtEnd {
    set line=in.ReadLine()
    set last=($e(line,*)="|")
    if last set sc=out.WriteLine(line)
    else  set sc=out.Write(line)
  }
  do in.%Close()
  set sc=out.%Save()
  quit sc
}
}

Hi Scott,

Have created an example state machine to walk three character segment names "AAA" or "AAN".

You can change the hl7 seperator via the parameter as annotated.

Class Test.ReframeHL7 [ Abstract ]
{
/// Broken line HL7 seperator replcaement.
/// Alternatively could use "\.br\""
Parameter hl7newline = "~";
ClassMethod Process(inStream As %Stream.FileCharacter, outStream As %Stream.TmpCharacter)
{
  do inStream.Rewind()
  set:'$IsObject(outStream) outStream=##class(%Stream.TmpCharacter).%New()
  set buffer="",state=0,step=0
  for {
    quit:inStream.AtEnd
    set char=inStream.Read(1)
    set uchar=$ZCVT(char,"U")
    if state=0,char=$C(13) {
      set state=1,buffer=char,step=1
      continue
    }
    if "01"[state,char=$C(10) {
      set state=2,buffer=buffer_char
      continue
    }
    if state=2,uchar=char,char?1{
      set state=3,buffer=buffer_char
      continue
    }
    if state=3,uchar=char,char?1{
      set state=4,buffer=buffer_char
      continue
    }
    if state=4,(((char?1A)&&(uchar=char))||(char?1N)) {
      set state=5,buffer=buffer_char
      continue
    }
    if state=5,char="|" {
      set state=0
      do outStream.Write(buffer_char)
      set buffer="",step=0
      continue
    }
    if state {
      set state=0
      do outStream.Write(..#hl7newline_$E(buffer,step+2,*)_char)
      set buffer=""
      continue
    } 
    if $L(buffer) {
        do outStream.Write(buffer)
        set buffer=""
    }
    set state=0,step=0
    do outStream.Write(char)
  }
  do:$L(buffer) outStream.Write(buffer)
}
 
/// set tSC=##class(Test.ReframeHL7).Test(inFilename,outFilename)
ClassMethod Test(inFilename, outFilename) As %Status
{
  #dim inFile as %IO.FileStream=##class(%IO.FileStream).%New()
  set tSC=inFile.Open(inFilename,"RS")
  quit:$$$ISERR(tSC) tSC
  #dim outFile as %IO.FileStream=##class(%IO.FileStream).%New()
  set tSC=outFile.Open(outFilename,"NWS")
  quit:$$$ISERR(tSC) tSC
  Do ..Process(inFile,outFile)
  Do outFile.Flush()
  Do outFile.Close()
  Do inFile.Close()
  quit $$$OK
}

}

Cheers,

Alex

Hi Scott,

Minimal sub-classing could be like the following:

Note: If there is no modification, it simply presents the original unmodified filestream.

 Class Test.ReframeService Extends EnsLib.HL7.Service.FileService
{
/// Broken line HL7 seperator replcaement.
/// Alternatively could use "\.br\""
Parameter hl7newline = "~";

Method OnProcessInput(pFileStream As %CharacterStream, Output pOutput As %RegisteredObject) As %Status
{
  do ##class(Test.ReframeService).Reframe(pFileStream)
  Quit ##super(.pFileStream,.pOutput)
}

ClassMethod Reframe(inStream As %Stream.FileCharacter)
{
  do inStream.Rewind()
  set outStream=##class(%Stream.TmpCharacter).%New()
  set buffer="",state=0,step=0,modified=0
  for {
    quit:inStream.AtEnd
    set char=inStream.Read(1)
    set uchar=$ZCVT(char,"U")
    if state=0,char=$C(13) {
      set state=1,buffer=char,step=1
      continue
    }
    if "01"[state,char=$C(10) {
      set state=2,buffer=buffer_char
      continue
    }
    if state=2,uchar=char,char?1{
      set state=3,buffer=buffer_char
      continue
    }
    if state=3,uchar=char,char?1{
      set state=4,buffer=buffer_char
      continue
    }
    if state=4,(((char?1A)&&(uchar=char))||(char?1N)) {
      set state=5,buffer=buffer_char
      continue
    }
    if state=5,char="|" {
      set state=0
      do outStream.Write(buffer_char)
      set buffer="",step=0
      continue
    }
    if state {
      set state=0,modified=1
      do outStream.Write(..#hl7newline_$E(buffer,step+2,*)_char)
      set buffer=""
      continue
    } 
    if $L(buffer) {
      do outStream.Write(buffer)
      set buffer=""
    }
    set state=0,step=0
    do outStream.Write(char)
  }
  do:$L(buffer) outStream.Write(buffer)
  do inStream.Rewind()
  if modified {
    do outStream.Rewind()
    do inStream.CopyFromAndSave(outStream)
    do inStream.Rewind()
  }
}

}