/// <summary> /// Parses all interchanges from an X12 document /// </summary> /// <param name="stream">Stream pointing to source X12 data</param> /// <param name="encoding">Stream encoding for reading data</param> /// <returns><see cref="Interchange"/> collection parsed from X12</returns> /// <exception cref="InvalidOperationException">Thrown on any missing segments or parent IDs</exception> public List <Interchange> ParseMultiple(Stream stream, Encoding encoding) { var envelopes = new List <Interchange>(); using (var reader = new X12StreamReader(stream, encoding, this.ignoredChars)) { var envelop = new Interchange(this.specFinder, reader.CurrentIsaSegment); envelopes.Add(envelop); Container currentContainer = envelop; FunctionGroup fg = null; Transaction tr = null; var hloops = new Dictionary <string, HierarchicalLoop>(); string segmentString = reader.ReadNextSegment(); string segmentId = reader.ReadSegmentId(segmentString); int segmentIndex = 1; var containerStack = new Stack <string>(); while (segmentString.Length > 0) { switch (segmentId) { case "ISA": envelop = new Interchange(this.specFinder, segmentString + reader.Delimiters.SegmentTerminator); envelopes.Add(envelop); currentContainer = envelop; fg = null; tr = null; hloops = new Dictionary <string, HierarchicalLoop>(); break; case "IEA": if (envelop == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMismatchSegment, segmentString, "ISA")); } envelop.SetTerminatingTrailerSegment(segmentString); break; case "GS": if (envelop == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMissingPrecedingSegment, segmentString, "ISA")); } currentContainer = fg = envelop.AddFunctionGroup(segmentString); break; case "GE": if (fg == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMismatchSegment, segmentString, "GS")); } fg.SetTerminatingTrailerSegment(segmentString); fg = null; break; case "ST": if (fg == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMissingGsSegment, segmentString)); } segmentIndex = 1; currentContainer = tr = fg.AddTransaction(segmentString); hloops = new Dictionary <string, HierarchicalLoop>(); break; case "SE": if (tr == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMismatchSegment, segmentString, "ST")); } tr.SetTerminatingTrailerSegment(segmentString); tr = null; break; case "HL": var hierarchicalLoopSegment = new Segment(null, reader.Delimiters, segmentString); string id = hierarchicalLoopSegment.GetElement(1); string parentId = hierarchicalLoopSegment.GetElement(2); string levelCode = hierarchicalLoopSegment.GetElement(3); while (!(currentContainer is HierarchicalLoopContainer hlCurrentContainer && hlCurrentContainer.AllowsHierarchicalLoop(levelCode))) { if (currentContainer.Parent != null) { currentContainer = currentContainer.Parent; } else { throw new InvalidOperationException(string.Format( Resources.X12ParserInvalidHLoopSpecification, segmentString, tr.ControlNumber)); } } bool parentFound = false; if (!string.IsNullOrEmpty(parentId)) { if (hloops.ContainsKey(parentId)) { parentFound = true; currentContainer = hloops[parentId].AddHLoop(segmentString); } else { if (this.throwExceptionOnSyntaxErrors) { throw new InvalidOperationException(string.Format(Resources.X12ParserMissingParentIdError, id, parentId)); } this.OnParserWarning(new X12ParserWarningEventArgs { FileIsValid = false, InterchangeControlNumber = envelop.InterchangeControlNumber, FunctionalGroupControlNumber = fg.ControlNumber, TransactionControlNumber = tr.ControlNumber, SegmentPositionInInterchange = segmentIndex, Segment = segmentString, SegmentId = segmentId, Message = string.Format(Resources.X12ParserMissingParentIdWarning, id, parentId) }); } } if (string.IsNullOrEmpty(parentId) || !parentFound) { while (!(currentContainer is HierarchicalLoopContainer hlCurrentContainer && hlCurrentContainer.HasHierachicalSpecs())) { currentContainer = currentContainer.Parent; } currentContainer = ((HierarchicalLoopContainer)currentContainer).AddHLoop(segmentString); } if (hloops.ContainsKey(id)) { throw new InvalidOperationException(string.Format(Resources.X12ParserHLoopIdExists, segmentString, tr.ControlNumber, id)); } hloops.Add(id, (HierarchicalLoop)currentContainer); break; case "TA1": if (envelop == null) { throw new InvalidOperationException(string.Format(Resources.X12ParserMismatchSegment, segmentString, "ISA")); } envelop.AddSegment(segmentString); break; default: var originalContainer = currentContainer; containerStack.Clear(); while (currentContainer != null) { if (currentContainer.AddSegment(segmentString) != null) { if (segmentId == "LE") { currentContainer = currentContainer.Parent; } break; } if (currentContainer is LoopContainer loopContainer) { Loop newLoop = loopContainer.AddLoop(segmentString); if (newLoop != null) { currentContainer = newLoop; break; } if (currentContainer is Transaction tran) { if (this.throwExceptionOnSyntaxErrors) { throw new TransactionValidationException( Resources.X12ParserSegmentCannotBeIdentitied, tran.IdentifierCode, tran.ControlNumber, string.Empty, segmentString, segmentIndex, string.Join(",", containerStack)); } currentContainer = originalContainer; currentContainer.AddSegment(segmentString, true); this.OnParserWarning(new X12ParserWarningEventArgs { FileIsValid = false, InterchangeControlNumber = envelop.InterchangeControlNumber, FunctionalGroupControlNumber = fg.ControlNumber, TransactionControlNumber = tran.ControlNumber, SegmentPositionInInterchange = segmentIndex, SegmentId = segmentId, Segment = segmentString, Message = string.Format( Resources.X12ParserSegmentWarning, tran.IdentifierCode, tran.ControlNumber, segmentString, segmentIndex, string.Join(",", containerStack), containerStack.LastOrDefault()) }); break; } if (currentContainer is Loop containerLoop) { containerStack.Push(containerLoop.Specification.LoopId); } if (currentContainer is HierarchicalLoop hloop) { containerStack.Push($"{hloop.Specification.LoopId}[{hloop.Id}]"); } currentContainer = currentContainer.Parent; continue; } break; } break; } segmentString = reader.ReadNextSegment(); segmentId = reader.ReadSegmentId(segmentString); segmentIndex++; } return(envelopes); } }
public List <Interchange> ParseMultiple(Stream stream, Encoding encoding) { var envelopes = new List <Interchange>(); using (X12StreamReader reader = new X12StreamReader(stream, encoding)) { Interchange envelop = new Interchange(_specFinder, reader.CurrentIsaSegment); envelopes.Add(envelop); Container currentContainer = envelop; FunctionGroup fg = null; Transaction tr = null; Dictionary <string, HierarchicalLoop> hloops = new Dictionary <string, HierarchicalLoop>(); string segmentString = reader.ReadNextSegment(); string segmentId = reader.ReadSegmentId(segmentString); int segmentIndex = 1; while (segmentString.Length > 0) { switch (segmentId) { case "ISA": envelop = new Interchange(_specFinder, segmentString + reader.Delimiters.SegmentTerminator); envelopes.Add(envelop); currentContainer = envelop; fg = null; tr = null; hloops = new Dictionary <string, HierarchicalLoop>(); break; case "IEA": if (envelop == null) { throw new InvalidOperationException(string.Format("Segment {0} does not have a matching ISA segment preceding it.", segmentString)); } envelop.SetTerminatingTrailerSegment(segmentString); break; case "GS": if (envelop == null) { throw new InvalidOperationException(String.Format("Segment '{0}' cannot occur before and ISA segment.", segmentString)); } currentContainer = fg = envelop.AddFunctionGroup(segmentString);; break; case "GE": if (fg == null) { throw new InvalidOperationException(String.Format("Segment '{0}' does not have a matching GS segment precending it.", segmentString)); } fg.SetTerminatingTrailerSegment(segmentString); fg = null; break; case "ST": if (fg == null) { throw new InvalidOperationException(string.Format("segment '{0}' cannot occur without a preceding GS segment.", segmentString)); } segmentIndex = 1; currentContainer = tr = fg.AddTransaction(segmentString); hloops = new Dictionary <string, HierarchicalLoop>(); break; case "SE": if (tr == null) { throw new InvalidOperationException(string.Format("Segment '{0}' does not have a matching ST segment preceding it.", segmentString)); } tr.SetTerminatingTrailerSegment(segmentString); tr = null; break; case "HL": Segment hlSegment = new Segment(null, reader.Delimiters, segmentString); string id = hlSegment.GetElement(1); string parentId = hlSegment.GetElement(2); if (parentId == "") { currentContainer = tr.AddHLoop(segmentString); } else { if (hloops.ContainsKey(parentId)) { currentContainer = hloops[parentId].AddHLoop(segmentString); } else { throw new InvalidOperationException(String.Format("Hierarchical Loop {0} expects Parent ID {1} which did not occur preceding it.", id, parentId)); } } if (hloops.ContainsKey(id)) { throw new InvalidOperationException(String.Format("Hierarchical Loop {0} cannot be added to transaction {1} because the ID {2} already exists.", segmentString, tr.ControlNumber, id)); } hloops.Add(id, (HierarchicalLoop)currentContainer); break; case "TA1": // Technical acknowledgement if (envelop == null) { throw new InvalidOperationException(string.Format("Segment {0} does not have a matching ISA segment preceding it.", segmentString)); } envelop.AddSegment(segmentString); break; default: while (currentContainer != null) { if (currentContainer.AddSegment(segmentString) != null) { break; } else { if (currentContainer is LoopContainer) { LoopContainer loopContainer = (LoopContainer)currentContainer; Loop newLoop = loopContainer.AddLoop(segmentString); if (newLoop != null) { currentContainer = newLoop; break; } else { if (currentContainer is Transaction) { var tran = (Transaction)currentContainer; throw new TransactionValidationException( "Segment '{3}' in segment position {4} within transaction '{1}' cannot be identified within the supplied specification for transaction set {0}.", tran.IdentifierCode, tran.ControlNumber, "", segmentString, segmentIndex); } else { currentContainer = currentContainer.Parent; continue; } } } else { break; } } } break; } segmentString = reader.ReadNextSegment(); segmentId = reader.ReadSegmentId(segmentString); segmentIndex++; } return(envelopes); } }
public List <Interchange> ParseMultiple(Stream stream, Encoding encoding) { var envelopes = new List <Interchange>(); using (X12StreamReader reader = new X12StreamReader(stream, encoding, _ignoredChars)) { Interchange envelop = new Interchange(_specFinder, reader.CurrentIsaSegment); envelopes.Add(envelop); Container currentContainer = envelop; FunctionGroup fg = null; Transaction tr = null; Dictionary <string, HierarchicalLoop> hloops = new Dictionary <string, HierarchicalLoop>(); string segmentString = reader.ReadNextSegment(); string segmentId = reader.ReadSegmentId(segmentString); int segmentIndex = 1; Stack <string> containerStack = new Stack <string>(); while (segmentString.Length > 0) { switch (segmentId) { case "ISA": envelop = new Interchange(_specFinder, segmentString + reader.Delimiters.SegmentTerminator); envelopes.Add(envelop); currentContainer = envelop; fg = null; tr = null; hloops = new Dictionary <string, HierarchicalLoop>(); break; case "IEA": if (envelop == null) { throw new InvalidOperationException(string.Format("Segment {0} does not have a matching ISA segment preceding it.", segmentString)); } envelop.SetTerminatingTrailerSegment(segmentString); break; case "GS": if (envelop == null) { throw new InvalidOperationException(String.Format("Segment '{0}' cannot occur before and ISA segment.", segmentString)); } currentContainer = fg = envelop.AddFunctionGroup(segmentString);; break; case "GE": if (fg == null) { throw new InvalidOperationException(String.Format("Segment '{0}' does not have a matching GS segment precending it.", segmentString)); } fg.SetTerminatingTrailerSegment(segmentString); fg = null; break; case "ST": if (fg == null) { throw new InvalidOperationException(string.Format("segment '{0}' cannot occur without a preceding GS segment.", segmentString)); } segmentIndex = 1; currentContainer = tr = fg.AddTransaction(segmentString); hloops = new Dictionary <string, HierarchicalLoop>(); break; case "SE": if (tr == null) { throw new InvalidOperationException(string.Format("Segment '{0}' does not have a matching ST segment preceding it.", segmentString)); } tr.SetTerminatingTrailerSegment(segmentString); tr = null; break; case "HL": Segment hlSegment = new Segment(null, reader.Delimiters, segmentString); string id = hlSegment.GetElement(1); string parentId = hlSegment.GetElement(2); string levelCode = hlSegment.GetElement(3); while (!(currentContainer is HierarchicalLoopContainer) || !((HierarchicalLoopContainer)currentContainer).AllowsHierarchicalLoop(levelCode)) { if (currentContainer.Parent != null) { currentContainer = currentContainer.Parent; } else { throw new InvalidOperationException(String.Format("Heierchical Loop {0} cannot be added to transaction set {1} because it's specification cannot be identified.", segmentString, tr.ControlNumber)); } } bool parentFound = false; if (parentId != "") { if (hloops.ContainsKey(parentId)) { parentFound = true; currentContainer = hloops[parentId].AddHLoop(segmentString); } else { if (_throwExceptionOnSyntaxErrors) { throw new InvalidOperationException(String.Format("Hierarchical Loop {0} expects Parent ID {1} which did not occur preceding it. To change this to a warning, pass throwExceptionOnSyntaxErrors = false to the X12Parser constructor.", id, parentId)); } else { OnParserWarning(new X12ParserWarningEventArgs { FileIsValid = false, InterchangeControlNumber = envelop.InterchangeControlNumber, FunctionalGroupControlNumber = fg.ControlNumber, TransactionControlNumber = tr.ControlNumber, SegmentPositionInInterchange = segmentIndex, Segment = segmentString, SegmentId = segmentId, Message = String.Format("Hierarchical Loop {0} expects Parent ID {1} which did not occur preceding it. This will be parsed as if it has no parent, but the file may not be valid.", id, parentId) }); } } } if (parentId == "" || !parentFound) { while (!(currentContainer is HierarchicalLoopContainer && ((HierarchicalLoopContainer)currentContainer).HasHierachicalSpecs())) { currentContainer = currentContainer.Parent; } currentContainer = ((HierarchicalLoopContainer)currentContainer).AddHLoop(segmentString); //hloops = new Dictionary<string, HierarchicalLoop>(); } if (hloops.ContainsKey(id)) { throw new InvalidOperationException(String.Format("Hierarchical Loop {0} cannot be added to transaction {1} because the ID {2} already exists.", segmentString, tr.ControlNumber, id)); } hloops.Add(id, (HierarchicalLoop)currentContainer); break; case "TA1": // Technical acknowledgement if (envelop == null) { throw new InvalidOperationException(string.Format("Segment {0} does not have a matching ISA segment preceding it.", segmentString)); } envelop.AddSegment(segmentString); break; default: var originalContainer = currentContainer; containerStack.Clear(); while (currentContainer != null) { if (currentContainer.AddSegment(segmentString) != null) { if (segmentId == "LE") { currentContainer = currentContainer.Parent; } break; } else { if (currentContainer is LoopContainer) { LoopContainer loopContainer = (LoopContainer)currentContainer; Loop newLoop = loopContainer.AddLoop(segmentString); if (newLoop != null) { currentContainer = newLoop; break; } else { if (currentContainer is Transaction) { var tran = (Transaction)currentContainer; if (_throwExceptionOnSyntaxErrors) { throw new TransactionValidationException( "Segment '{3}' in segment position {4} within transaction '{1}' cannot be identified within the supplied specification for transaction set {0} in any of the expected loops: {5}. To change this to a warning, pass throwExceptionOnSyntaxErrors = false to the X12Parser constructor.", tran.IdentifierCode, tran.ControlNumber, "", segmentString, segmentIndex, string.Join(",", containerStack)); } else { currentContainer = originalContainer; currentContainer.AddSegment(segmentString, true); OnParserWarning(new X12ParserWarningEventArgs { FileIsValid = false, InterchangeControlNumber = envelop.InterchangeControlNumber, FunctionalGroupControlNumber = fg.ControlNumber, TransactionControlNumber = tran.ControlNumber, SegmentPositionInInterchange = segmentIndex, SegmentId = segmentId, Segment = segmentString, Message = string.Format("Segment '{3}' in segment position {4} within transaction '{1}' cannot be identified within the supplied specification for transaction set {0} in any of the expected loops: {5}. It will be added to loop {6}, but this may invalidate all subsequent segments.", tran.IdentifierCode, tran.ControlNumber, "", segmentString, segmentIndex, string.Join(",", containerStack), containerStack.LastOrDefault()) }); break; } } else { if (currentContainer is Loop) { containerStack.Push(((Loop)currentContainer).Specification.LoopId); } if (currentContainer is HierarchicalLoop) { var hloop = ((HierarchicalLoop)currentContainer); containerStack.Push(string.Format("{0}[{1}]", hloop.Specification.LoopId, hloop.Id)); } currentContainer = currentContainer.Parent; continue; } } } else { break; } } } break; } segmentString = reader.ReadNextSegment(); segmentId = reader.ReadSegmentId(segmentString); segmentIndex++; } return(envelopes); } }