/// <summary> /// Read xml file and construct IFatpipeDocument. /// Xml file reader will traverse Xml files and for each element /// match it with current pluglet. If match fails then it tries to /// find matching pluglet (similar to X12). /// </summary> /// <returns></returns> public IFatpipeDocument ReadFile(Stream xmlFileStream, IDocumentPlug documentPlug) { if (xmlFileStream == null) { throw new ArgumentNullException("xmlFileStream", "Xml file stream cannot be null"); } if (documentPlug == null) { throw new ArgumentNullException("documentPlug", "Document plug cannot be null"); } string location = "XmlFileReader.ReadFile"; Logger.Debug(location, "Start"); BeautifiedOriginalPayload = string.Empty; CurrentElementNumber = 0; TotalPayloadLength = 0; CurrentLinePayloadStart = 0; CurrentLinePayloadEnd = 0; CurrentLevel = 0; Stopwatch sw = new Stopwatch(); sw.Start(); errors = new InterchangeErrors(); // Since xml file doesn't have concept of ST/SE, ans we want to use InterchangeErrors for reporting purpose // create dummy transaction set details Errors.AddTransactionSetDetails(1, "", "", true); IPluglet currentPluglet = documentPlug.RootPluglet; currentPluglet.ResetCurrentOccurances(); currentPluglet.InitializeStartSegmentList(); FatpipeDocumentInst = new FatpipeDocument(); FatpipeDocumentInst.DocumentPlug = documentPlug; FatpipeDocumentInst.RootFragment = currentPluglet.ConstructDocumentFragment(null, null); IDocumentFragment currentDocumentFragment = FatpipeDocumentInst.RootFragment; IDocumentFragment newDocumentFragment = null; bool isLeafNode = false; try { XmlTextReader xmlReader = new XmlTextReader(xmlFileStream); // If some element doesn't match document plutlet then stop // TODO: Should we try to match other elements? If yes, which pluglet to start with? // Also we need to ignore this entire element bool stopProcessing = false; while (xmlReader.Read()) { switch (xmlReader.NodeType) { case XmlNodeType.Element: isLeafNode = false; AddStartElementToPayload(xmlReader.Name, xmlReader.IsEmptyElement); if (xmlReader.IsEmptyElement) { break; } if (stopProcessing == false) { currentDocumentFragment = ConstructNewDocumentFragment(xmlReader.Name, currentPluglet, currentDocumentFragment); } // If some element doesn't match document plutlet then stop // TODO: Should we try to match other elements? If yes, which pluglet to start with? // Also we need to ignore this entire element if (currentDocumentFragment == null) { stopProcessing = true; } else { currentPluglet = currentDocumentFragment.Pluglet; } CurrentLevel++; CurrentElementNumber++; break; case XmlNodeType.Text: isLeafNode = true; AddValueToPayload(xmlReader.Value); if (stopProcessing == false) { currentDocumentFragment.Value = xmlReader.Value; } // Assumption: Leaf nodes are on same line and non-leaf nodes are 1-per line (separate line for start and end element) // If this assumption is wrong then we can construct the xml in string format to match fulfill above assumption // and then Ux can use this string version of xml to highlight the errors. CurrentElementNumber--; // Decrement since leaf level elements are one line, so we need to increment element on endElement only. break; case XmlNodeType.EndElement: CurrentLevel--; AddEndElementToPayload(xmlReader.Name, isLeafNode); if (stopProcessing == false) { // Check if all mandatory segments were present CheckMissingMandatoryElements(currentPluglet, currentDocumentFragment); currentDocumentFragment = currentDocumentFragment.Parent; currentPluglet = currentPluglet.Parent; } CurrentElementNumber++; isLeafNode = false; break; default: break; } } } catch (XmlException xmlException) { // TODO: Pass start and end postition Errors.AddGenericError(currentPluglet == null ? "N/A" : currentPluglet.Name, X12ErrorCode.UnexpectedSegmentCode, string.Format("Error parsing XML document: {0}", xmlException.Message), CurrentElementNumber / 2, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength); } catch (Exception exception) { // TODO: Pass start and end postition (for all Errors.Add* calls) in this file. Errors.AddGenericError(currentPluglet == null ? "N/A" : currentPluglet.Name, X12ErrorCode.UnexpectedSegmentCode, "Internal error occurred, please contact Maarg", CurrentElementNumber / 2, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength); Logger.Error(location, EventId.XmlReaderUnhandledException, "Error occured during xml file processing: {0}", exception.ToString()); } FatpipeDocumentInst.BeautifiedOriginalPayloadBody = BeautifiedOriginalPayload; sw.Stop(); Logger.Debug(location, "Stop - Elapsed time {0} ms", sw.ElapsedMilliseconds); return(FatpipeDocumentInst); }
/// <summary> /// Find corrosponding Pluglet for given segmentname and create new segment /// </summary> /// <param name="segmentName"></param> /// <param name="segmentDetails"></param> private void CreateAndAddNewSegment(string segmentName, string[] segmentDetails) { const string firstSegmentName = "ST"; string errorMsgs = string.Empty; IPluglet nextPluglet; string location = "EDIReader.CreateAndAddNewSegment"; Logger.Debug(location, "Adding {0} segment", segmentName); string missingMandatorySegments; nextPluglet = CurrentPluglet.GetSegmentPluglet(segmentName, segmentDetails, firstSegmentName, out missingMandatorySegments); // First add missing mandatory segment errors if (nextPluglet != null && !string.IsNullOrWhiteSpace(missingMandatorySegments)) { string error = string.Format("Missing mandatory segments ({0}) between {1} and {2}" , missingMandatorySegments, CurrentPluglet.Tag, segmentName); if (FatpipeDocumentInst.Errors == null) { FatpipeDocumentInst.Errors = new List <string>(); } FatpipeDocumentInst.Errors.Add(error); Logger.Error("EDIReader.CreateAndAddNewSegment", EventId.EDIReaderMissingMandatorySegment, "{0} - {1}", GetCurrentPosContext(), error); EdiErrorType errorType = nextPluglet.IsIgnore ? EdiErrorType.Warning : EdiErrorType.Error; foreach (string segment in missingMandatorySegments.Split(',')) { Errors.AddSegmentError(segmentName, X12ErrorCode.MandatorySegmentMissingCode , string.Format("{0} : {1}", X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.MandatorySegmentMissingCode), segment) , SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, errorType); } } if (nextPluglet == null) { /* //TODO: Revisit following if condition - do we really want to ignore ISA/GS segment missing in schema? * if (segmentName != "ISA" && segmentName != "GS") * { * errors = string.Format("{0} segment not found in schema after {1}", segmentName, CurrentPluglet.Name); * * Logger.Error(location, EventId.EDIReaderUnknownSegment, "{0} - {1}", GetCurrentPosContext(), errors); * Errors.AddSegmentError(segmentName, X12ErrorCode.UnrecognizedSegmentIDCode * , X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnrecognizedSegmentIDCode), SegmentNumber); * } */ //experimenting with unknown here above is actual //IPluglet unknown = new Pluglet("UNRECOGNIZED_SEGMENT", "Unknown Segment", PlugletType.Segment, CurrentPluglet.Parent); IPluglet unknown = new Pluglet( new PlugletInput() { Name = "UNRECOGNIZED_SEGMENT", Definition = "Unknown Segment", Type = PlugletType.Segment, Parent = CurrentPluglet.Parent, IsIgnore = false, AddToParent = false, IsTagSameAsName = true, }); // IPluglet x = new Pluglet("child"+i, "Unknown Data", PlugletType.Data, unknown); //unknown.Children.Add(x); //} //DocumentFragment newFragment = unknown.ConstructDocumentFragment(segmentDetails, false, EDIDelimiters, out errors); errorMsgs = string.Format("{0} segment not found in schema after {1}", segmentName, CurrentPluglet.Name); Errors.AddSegmentError(segmentName, X12ErrorCode.UnrecognizedSegmentIDCode , X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnrecognizedSegmentIDCode), SegmentNumber , this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, EdiErrorType.Error); DocumentFragment newFragment = new DocumentFragment() { Pluglet = unknown, Children = new List <IDocumentFragment>(), }; IPluglet childPluglet = new Pluglet("Data", "Data", PlugletType.Data, null); DocumentFragment child = new DocumentFragment() { Parent = newFragment, Pluglet = childPluglet, Children = null, SequenceNumber = SegmentNumber, StartOffset = this.CurrentSegmentStartPos, EndOffset = this.CurrentSegmentEndPos - 1, }; newFragment.Children.Add(child); child.Value = CurrentSegment; if (newFragment == null) { errorMsgs = string.Format("{0} DocumentFragment creation failed. Errors: {1}", segmentName, errorMsgs); Logger.Error(location, EventId.EDIReaderDocFragmentCreation, "{0} - {1}", GetCurrentPosContext(), errorMsgs); //TODO: what should be the code here? //Errors.AddGenericError(segmentName, X12ErrorCode.??? } else { ((DocumentFragment)FatpipeDocumentInst.RootFragment).AddDocumentFragment(newFragment); // CurrentPluglet = newFragment.Pluglet; } //experimenting with unknown here } else { if (nextPluglet.RepetitionInfo.MaxOccurs == 0) { Errors.AddSegmentError(segmentName, X12ErrorCode.UnexpectedSegmentCode , string.Format("{0} : {1}", X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnexpectedSegmentCode), nextPluglet.Tag) , SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, EdiErrorType.Error); } else { DocumentFragment newFragment = nextPluglet.ConstructDocumentFragment(segmentDetails, false, EDIDelimiters, SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, ref errors, out errorMsgs); if (newFragment == null) { //errorMsgs = string.Format("{0} DocumentFragment creation failed. Errors: {1}", segmentName, errorMsgs); Logger.Error(location, EventId.EDIReaderDocFragmentCreation, "{0} - {1}", GetCurrentPosContext(), errorMsgs); // TODO: Replace UnexpectedSegmentCode with appropriate one Errors.AddGenericError(segmentName, X12ErrorCode.UnexpectedSegmentCode, errorMsgs, SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos); } else { ((DocumentFragment)FatpipeDocumentInst.RootFragment).AddDocumentFragment(newFragment); CurrentPluglet = newFragment.Pluglet; } } } if (!string.IsNullOrEmpty(errorMsgs)) { if (FatpipeDocumentInst.Errors == null) { FatpipeDocumentInst.Errors = new List <string>(); } FatpipeDocumentInst.Errors.Add(errorMsgs); } }