This project has moved and is read-only. For the latest updates, please go here.

X12Parser.UnbundleByLoop() and Transaction Trailer Segments.

Aug 4, 2014 at 11:04 PM
I am using the unbundling aspect of X12Parser, but noticed that it does not include SE transaction trailer segments in it's output. Tracing this back, I believe this is due to the fact that X12StreamReader.ReadNextTransaction() does not include the trailing SE segment:
        public X12FlatTransaction ReadNextTransaction()
        {
            StringBuilder segments = new StringBuilder();

            string segmentString = ReadNextSegment();
            string segmentId = ReadSegmentId(segmentString);
            do
            {
                switch (segmentId)
                {
                    case "ISA":
                        _isaSegment = segmentString + _delimiters.SegmentTerminator;
                        break;
                    case "GS":
                        _gsSegment = segmentString + _delimiters.SegmentTerminator;
                        break;
                    case "IEA":
                    case "GE":
                        break;
                    default:
                        if (segmentId == "ST")
                            _transactionCode = SplitSegment(segmentString)[1];
                        segments.Append(segmentString);
                        segments.Append(_delimiters.SegmentTerminator);
                        break;
                }
                segmentString = ReadNextSegment();
                segmentId = ReadSegmentId(segmentString);
            } while (!string.IsNullOrEmpty(segmentString) && segmentId != "SE"); // transaction trailer segment

            return new X12FlatTransaction(
                CurrentIsaSegment,
                CurrentGsSegment,
                segments.ToString());
        }
Therefore, the TerminationTrailerSegment in X12Parser.ParseMultiple() does not get set. Afterward, when we serialize the unbundled loop back to X12, the SE segment does not get emitted.

As an example,

Original:
REF*LU*484345
LX*1
SV1*HC:99214*60*UN*1*11**1
DTP*472*RD8*20120921-20120921
REF*6R*1134
SE*32*000000248
GE*1*248
IEA*1*000000248
Unbundled:
REF*LU*484345
LX*1
SV1*HC:99214*60*UN*1*11**1
DTP*472*RD8*20120921-20120921
REF*6R*1134
GE*1*248
IEA*1*000000248
I need to ask advice about where best to remedy this. I think modifying ReadNextTransaction() will possibly introduce a lot of issues, as it is used in a lot of places. It's current semantics cannot be blindly changed without in depth knowledge.

I can make the required modifications and send you a pull request, but wanted to seek advice on the matter first.
Aug 5, 2014 at 6:20 PM
As a stop gap, I implemented a custom ReadNextTransaction() in my helper class:
        protected void Initialize() {
            dataStream.Seek(0, SeekOrigin.Begin);

            X12StreamReader x12Reader = new X12StreamReader(dataStream, new UTF8Encoding());
            X12Parser parser = new X12Parser(specFinder, false);
            List<Interchange> interchanges = new List<Interchange>();

            string segments = ReadNextTransaction(x12Reader);

            while (!string.IsNullOrWhiteSpace(segments)) {
                var iList = parser.ParseMultiple(segments);

                if (iList != null && iList.Count > 0) {
                    if (loopId.Trim().ToUpper() == "ST") {
                        interchanges.Add(iList.First());
                    } else {
                        interchanges.AddRange(parser.UnbundleByLoop(iList.First(), loopId));
                    }
                }

                segments = ReadNextTransaction(x12Reader);
            }

            for (int i = 0; i < interchanges.Count; i++) {
                IDS.IO.TempFileStream stream = new IDS.IO.TempFileStream();
                using (var writer = stream.GetStreamWriter(new UTF8Encoding())) {
                    writer.Write(interchanges[i].SerializeToX12(newlines));
                    writer.Flush();
                }

                stream.Flush();
                stream.Rewind();

                transactions.Add(stream);
            }
        }

        protected string ReadNextTransaction(X12StreamReader x12Reader) {
            StringBuilder segments = new StringBuilder();
            char segTerminator = x12Reader.Delimiters.SegmentTerminator;
            char elemSeparator = x12Reader.Delimiters.ElementSeparator;
            string isa = x12Reader.CurrentIsaSegment;
            string gs = x12Reader.CurrentGsSegment;

            string segmentString = x12Reader.ReadNextSegment();
            string segmentId = x12Reader.ReadSegmentId(segmentString);

            do {
                switch (segmentId) {
                    case "ISA":
                        isa = segmentString;
                        break;

                    case "GS":
                        gs = segmentString;
                        break;

                    case "IEA":
                        break;

                    case "GE":
                        break;

                    default:
                        segments.Append(segmentString);
                        segments.Append(segTerminator);

                        break;
                }

                segmentString = x12Reader.ReadNextSegment();
                segmentId = x12Reader.ReadSegmentId(segmentString);

            } while (!string.IsNullOrEmpty(segmentString) && segmentId != "SE");

            if (segments.Length == 0) {
                return string.Empty;
            }

            if (segmentId == "SE") {
                segments.Append(segmentString);
                segments.Append(segTerminator);
            }

            StringBuilder sb = new StringBuilder(segments.Length + 512);

            if (!string.IsNullOrWhiteSpace(isa)) {
                sb.Append(isa);
            }

            if (!string.IsNullOrWhiteSpace(gs)) {
                sb.Append(gs);
                sb.Append(segTerminator);
            }

            sb.Append(segments);

            if (!string.IsNullOrWhiteSpace(gs)) {
                string[] gsElements = gs.Split(elemSeparator);
                sb.AppendFormat("GE{1}{2}{1}{3}{0}", segTerminator, elemSeparator, "1", gsElements[6]);
            }

            if (!string.IsNullOrWhiteSpace(isa)) {
                string[] isaElements = isa.Split(elemSeparator);
                sb.AppendFormat("IEA{1}1{1}{2}{0}", segTerminator, elemSeparator, isaElements[13]);
            }

            return sb.ToString();
        }
This produces the desired result:
REF*LU*484345
LX*1
SV1*HC:99214*60*UN*1*11**1
DTP*472*RD8*20120921-20120921
REF*6R*1134
SE*32*000000248
GE*1*248
IEA*1*000000248