/// <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);
            }
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 3
0
        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);
            }
        }