/// <summary> /// Parses a segment /// </summary> /// <param name="line">The segment line.</param> /// <param name="grammar">The segment grammar.</param> /// <param name="interchangeContext">The interchange context.</param> /// <returns>The parsed xml.</returns> private static XElement Parse(ParseTree grammar, string line, InterchangeContext interchangeContext) { if (!grammar.IsSegment) { throw new Exception("Not a segment."); } XNamespace ns = interchangeContext.TargetNamespace; var result = new XElement(ns + grammar.Name); // Gets the composite data elements from the segment string var dataElements = EdiHelper.GetEdiCompositeDataElements(line, interchangeContext).ToList(); // Index the composite data elements from the class definition var indexedGrammar = grammar.Children.Select((g, p) => new { Grammar = g, Position = p }).ToList(); // Index the composite data elements from the edi string var indexedValues = dataElements.Select((v, p) => new { Value = v, Position = p }).ToList(); // This will try to parse the edi string into the class definition // Load a parse tree against each value // If there are more values in the edi string than in the class definition - they will be ignored // If there are less values in the edi string than in the class definition - it will throw an exception var indexedList = from ig in indexedGrammar from iv in indexedValues where ig.Position == iv.Position select new { ig.Grammar, iv.Value, ig.Position }; foreach (var dataElement in indexedList) { // Skip the blank elements // This massively reduces the generated XML if (string.IsNullOrEmpty(dataElement.Value)) { // Don't skip for header segments as they are positional if (!grammar.IsEnvelope) { continue; } } // If the current element is out of the range of elemnts defined in the definition class, then it's a repetition // The repetitions are always for the last defined element var elementGrammar = dataElement.Position >= grammar.Children.Count ? grammar.Children.Last() : grammar.Children[dataElement.Position]; // Handle the repetitions var elementRepetitions = grammar.IsEnvelope ? new[] { dataElement.Value } : EdiHelper.GetRepetitions(dataElement.Value, interchangeContext); // Parse each repetition foreach (var elementRepetition in elementRepetitions) { result.Add(ParseElement(elementGrammar, elementRepetition, interchangeContext)); } } return(result); }
/// <summary> /// Lexical analysis of the segments /// </summary> public void Analyze() { var message = new List <string>(); var envelope = new List <string>(); // Loads all messages in memory foreach (var segment in EdiHelper.GetEdiSegments(_ediString, InterchangeContext)) { switch (EdiHelper.GetSegmentName(segment, InterchangeContext)) { case EdiSegments.Una: break; case EdiSegments.Unb: case EdiSegments.Isa: CreateInterchangeHeader(segment); break; case EdiSegments.Unz: case EdiSegments.Iea: CreateInterchangeTrailer(segment); break; case EdiSegments.Ung: CreateGroupHeader(segment); break; case EdiSegments.Gs: CreateGroupHeader(segment); envelope.Add(segment); break; case EdiSegments.Une: case EdiSegments.Ge: CreateGroupTrailer(segment); envelope.Clear(); break; case EdiSegments.Unh: case EdiSegments.St: message.Add(segment); envelope.Add(segment); break; case EdiSegments.Unt: case EdiSegments.Se: message.Add(segment); CreateMessage(message, envelope); // For X12 the ST segment is included in the headers // Once the message is parsed - it's removed envelope.Remove(envelope.Last()); message.Clear(); break; default: message.Add(segment); break; } } }
/// <summary> /// Converts the interchange to edi message. /// </summary> /// <param name="context"> /// The interchange context. /// This sets the non format default separators. /// </param> /// <returns> /// The edi message. /// </returns> public List <string> ToEdi(InterchangeContext context = null) { var edifactLexer = new ToEdiLexer(EdiHelper.Serialize(this), context); edifactLexer.Analyze(); return(edifactLexer.Result); }
/// <summary> /// Converts the interchange to edi message. /// </summary> /// <param name="context"> /// The interchange context. /// This sets the non format default separators. /// </param> /// <returns> /// The edi message. /// </returns> public override List <string> ToEdi(InterchangeContext context = null) { var x12Lexer = new ToEdiLexer(EdiHelper.Serialize(this), context); x12Lexer.Analyze(); return(x12Lexer.Result); }
/// <summary> /// Converts edi interchange headers into message context. /// </summary> /// <param name="envelopes">The interchange headers.</param> /// <param name="interchangeContext">The interchange context.</param> /// <returns> /// The message context. /// </returns> private Tuple <string, string, string, EdiFormats> ToContextEdifact(IEnumerable <string> envelopes, InterchangeContext interchangeContext) { try { var unh = envelopes.Single(es => es.StartsWith(EdiSegments.Unh)); var ediCompositeDataElements = EdiHelper.GetEdiCompositeDataElements(unh, interchangeContext); var ediDataElements = EdiHelper.GetEdiComponentDataElements(ediCompositeDataElements[1], interchangeContext); return(new Tuple <string, string, string, EdiFormats>(ediDataElements[0], ediDataElements[1] + ediDataElements[2], null, EdiFormats.Edifact)); } catch (Exception ex) { throw new ParserException("Can't parse UNH segment.", ex); } }
/// <summary> /// Converts EDI interchange headers into message context. /// </summary> /// <param name="envelopes">The interchange headers.</param> /// <param name="interchangeContext">The interchange context.</param> private void ToContextX12(IEnumerable <string> envelopes, InterchangeContext interchangeContext) { var enumerable = envelopes as List <string> ?? envelopes.ToList(); string version; string origin; string format; string tag; try { var gs = enumerable.Single(es => es.StartsWith(EdiSegments.Gs)); var ediCompositeDataElementsGs = EdiHelper.GetEdiCompositeDataElements(gs, interchangeContext); version = ediCompositeDataElementsGs[7].Substring(0, 6); origin = ediCompositeDataElementsGs[7].Count() >= 10 ? ediCompositeDataElementsGs[7].Substring(6, 4) : null; format = HipaaHelper.IsHipaa(version + origin) ? EdiFormats.Hipaa.ToString() : EdiFormats.X12.ToString(); if (!HipaaHelper.IsHipaa(version + origin)) { origin = null; } } catch (Exception ex) { throw new ParserException("Can't parse GS segment.", ex); } try { var st = enumerable.Single(es => es.StartsWith(EdiSegments.St)); var ediCompositeDataElementsSt = EdiHelper.GetEdiCompositeDataElements(st, interchangeContext); tag = ediCompositeDataElementsSt[0]; } catch (Exception ex) { throw new ParserException("Can't parse ST segment.", ex); } Tag = tag; Version = version; Origin = origin; Format = ToFormat(format); }
/// <summary> /// Converts EDI interchange headers into message context. /// </summary> /// <param name="envelopes">The interchange headers.</param> /// <param name="interchangeContext">The interchange context.</param> private void ToContextEdifact(IEnumerable <string> envelopes, InterchangeContext interchangeContext) { try { var unh = envelopes.Single(es => es.StartsWith(EdiSegments.Unh)); var ediCompositeDataElements = EdiHelper.GetEdiCompositeDataElements(unh, interchangeContext); var ediDataElements = EdiHelper.GetEdiComponentDataElements(ediCompositeDataElements[1], interchangeContext); Tag = ediDataElements[0]; Version = ediDataElements[1] + ediDataElements[2]; Origin = null; Format = EdiFormats.Edifact; } catch (Exception ex) { throw new ParserException("Can't parse UNH segment.", ex); } }
/// <summary> /// Serialize the interchange into xml /// </summary> /// <returns> /// The serialized xml. /// </returns> public XElement Serialize() { return(EdiHelper.Serialize(this)); }
/// <summary> /// Parses a data element /// </summary> /// <param name="parseTree">The dataelement grammar.</param> /// <param name="value">The dataelement line.</param> /// <param name="interchangeContext"></param> /// <returns>The parsed xml.</returns> private static XElement ParseElement(ParseTree parseTree, string value, InterchangeContext interchangeContext) { if (value == null) { throw new ArgumentNullException("value"); } if (!parseTree.IsComplex && !parseTree.IsSimple) { throw new Exception("Not a data element."); } XNamespace ns = interchangeContext.TargetNamespace; var result = new XElement(ns + parseTree.Name); if (parseTree.IsComplex) { if (value == string.Empty) { // Only deal with blank values for envelope headers if (parseTree.IsEnvelope) { foreach (var dataElement in parseTree.Children) { var element = new XElement(ns + dataElement.Name); element.SetValue(string.Empty); result.Add(element); } } } else { // Get the simple data elements var componentDataElements = EdiHelper.GetEdiComponentDataElements(value, interchangeContext).ToList(); // Index the composite data elements from the class definition var indexedGrammar = parseTree.Children.Select((g, p) => new { Grammar = g, Position = p }).ToList(); // Index the composite data elements from the edi string var indexedValues = componentDataElements.Select((v, p) => new { Value = v, Position = p }).ToList(); // This will try to parse the edi string into the class definition // Load a parse tree against each value // If there are more values in the edi string than in the class definition - they will be ignored // If there are less values in the edi string than in the class definition - it will throw an exception var indexedList = from ig in indexedGrammar from iv in indexedValues where ig.Position == iv.Position select new { ig.Position, iv.Value }; // Index the list so we can position each element //var indexed = componentDataElements.Select((a, i) => new {Item = a, Position = i}).ToList(); foreach (var dataElement in indexedList) { // Skip blank data elements otherwise this will produce blank XML nodes if (string.IsNullOrEmpty(dataElement.Value)) { if (!parseTree.IsEnvelope) { continue; } } // Handle the repetitions // If the children the the edi straing are more than the class definition, // Then the diff are considered repetitions of the last child in the class definition var objectToParse = dataElement.Position >= parseTree.Children.Count ? parseTree.Children.Last() : parseTree.Children[dataElement.Position]; var element = new XElement(ns + objectToParse.Name); // Set the value and escape to prevent faulty XML element.SetValue(SecurityElement.Escape(dataElement.Value) ?? string.Empty); result.Add(element); } } } else { // Prevent faulty XML result.SetValue(SecurityElement.Escape(value) ?? string.Empty); } return(result); }
/// <summary> /// Initializes a new instance of the <see cref="Message"/> class. /// </summary> /// <param name="instance"> /// Edi object. /// </param> /// <example> /// Set UNT segments count. /// <code lang="C#"> /// var mInvoic = new M_INVOIC(); /// // ... build the message /// /// var msg = new Message(mInvoic); /// var segCount = msg.Item.Descendants().Count(d => d.Name.LocalName.StartsWith("S_")); /// /// var nmn = new XmlNamespaceManager(new NameTable()); /// nmn.AddNamespace("p", "www.edifabric.com/edifact"); /// /// var untSegCount = msg.Item.XPathSelectElement("./p:S_UNT/p:D_0074_1", nmn); /// untSegCount.SetValue(segCount); /// </code> /// </example> public Message(object instance) { Context = new MessageContext(instance.GetType()); Item = EdiHelper.Serialize(instance); }