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?
Comments
Just to understand your requirements correctly.
- a linebreak $c(13,10) would only be acceptable if it follows a segment terminator "|"
- IF YES Is this just a pipe | or a double pipe || as in your example?
This could be a processing rule to check the last chars of the line
and ignoré the linebreak at a mismatch.
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?1A {
set state=3,buffer=buffer_char
continue
}
if state=3,uchar=char,char?1A {
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
Thanks for the suggestions, so I would need to add this to a copy of EnsLib.HL7.Service.FileService to call as it reads in the message? Or would I call a service then send it another service to parse and remove the misc characters before it starts reading it in as HL7?
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?1A {
set state=3,buffer=buffer_char
continue
}
if state=3,uchar=char,char?1A {
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()
}
}
}