/// <summary> /// Set atribute value on a DocumentFragment based on it's xPath. /// If intermediate nodes are not available then this function create those nodes too. /// </summary> /// <param name="currentDocument"></param> /// <param name="newFragment"></param> public static void AddDocumentFragment(this DocumentFragment document, string xPath, string value) { if (document == null) { throw new ArgumentNullException("document"); } if (string.IsNullOrEmpty(xPath)) { throw new ArgumentNullException("xPath"); } string attributeName = xPath.Substring(xPath.LastIndexOf(document.Pluglet.PathSeperator) + document.Pluglet.PathSeperator.Length); ILogger logger = LoggerFactory.Logger; logger.Debug("DocumentFragmentExtensions.AddDocumentFragment", "Adding attribute {0}", attributeName); DocumentFragment documentFragment = document.AddIntermediateDocumentFragment(xPath); if (documentFragment.Attributes == null) { documentFragment.Attributes = new Dictionary <string, string>(); } documentFragment.Attributes.Add(attributeName, value); logger.Debug("DocumentFragmentExtensions.AddDocumentFragment", "Adding attribute {0}", attributeName); }
/// <summary> /// Add new DocumentFragment based on it's xPath. If intermediate nodes are not available then this function create those nodes too. /// </summary> /// <param name="currentDocument"></param> /// <param name="newFragment"></param> public static void AddDocumentFragment(this DocumentFragment document, IDocumentFragment newFragment) { if (document == null) { throw new ArgumentNullException("document"); } if (newFragment == null) { throw new ArgumentNullException("newFragment"); } ILogger logger = LoggerFactory.Logger; logger.Debug("DocumentFragmentExtensions.AddDocumentFragment", "Adding document fragment {0}", newFragment.Name); DocumentFragment parentFragment = document.AddIntermediateDocumentFragment(newFragment.Pluglet.Path); if (parentFragment.Children == null) { parentFragment.Children = new List <IDocumentFragment>(); } parentFragment.Children.Add(newFragment); ((DocumentFragment)newFragment).Parent = parentFragment; logger.Debug("DocumentFragmentExtensions.AddDocumentFragment", "Added document fragment {0}", newFragment.Name); }
/// <summary> /// Construct DocumentFragment from IPluglet for non-leaf elements /// </summary> /// <param name="pluglet"></param> /// <param name="parent"></param> /// <returns></returns> public static DocumentFragment ConstructDocumentFragment(this IPluglet pluglet, IDocumentFragment parent, string value) { if (pluglet == null) { throw new ArgumentNullException("pluglet"); } ++pluglet.CurrentOccurrences; DocumentFragment documentFragment = new DocumentFragment() { Pluglet = pluglet, Parent = parent, Value = value, }; return(documentFragment); }
/// <summary> /// Construct DocumentFragment for leaf node parent and then create and attach leaf nodes to it. /// </summary> /// <param name="pluglet"></param> /// <param name="segmentDetails"></param> /// <param name="internalSegment"></param> /// <param name="ediDelimiters"></param> /// <param name="segmentStartIndex"></param> /// <param name="segmentEndIndex"></param> /// <param name="ediErrors"></param> /// <param name="error"></param> /// <returns></returns> public static DocumentFragment ConstructDocumentFragment(this IPluglet pluglet, string[] segmentDetails, bool internalSegment, Delimiters ediDelimiters, int segmentSeqNumber, long segmentStartIndex, long segmentEndIndex, ref InterchangeErrors ediErrors, out string error) { if (pluglet == null) { throw new ArgumentNullException("pluglet"); } if (segmentDetails == null) { throw new ArgumentNullException("segmentDetails"); } LoggerFactory.Logger.Info("PlugletExtensions.ConstructDocumentFragment", "Constructing {0} instance", pluglet.Tag); if (pluglet.Children == null) { error = string.Format("Pluglet {0} does not have childrens", pluglet.Name); return(null); } // -1 is required since SegmentDetails[0] is the SegmentName if (pluglet.Children.Count < segmentDetails.Length - 1) { error = string.Format("Document has {1} data elements, it is less than segment children count {2} as described in Spec", pluglet.Name, pluglet.Children.Count, segmentDetails.Length); return(null); } error = string.Empty; ++pluglet.CurrentOccurrences; DocumentFragment documentFragment = new DocumentFragment() { Pluglet = pluglet, Children = new List <IDocumentFragment>(), SequenceNumber = segmentSeqNumber, StartOffset = segmentStartIndex, EndOffset = segmentEndIndex, }; int plugletNum = 0; DocumentFragment dataFragment; IPluglet plugletChild; bool validateValue; long currentSegmentFieldStartIndex = segmentStartIndex; //SegmentNum start from 1 since SegmentDetails[0] is Segment name int segmentNum = 1; // if this is internal segment (composite segment - segment handing data and segment as children) then // start segmentDetails from 0 if (internalSegment == true) { segmentNum = 0; } EdiErrorType errorType = pluglet.IsIgnore ? EdiErrorType.Warning : EdiErrorType.Error; for (; segmentNum < segmentDetails.Length; segmentNum++, plugletNum++) { if (segmentNum != 0) { currentSegmentFieldStartIndex += segmentDetails[segmentNum - 1].Length + 1; } validateValue = false; plugletChild = pluglet.Children[plugletNum]; if (plugletChild.PlugletType == PlugletType.Data) { dataFragment = new DocumentFragment() { Parent = documentFragment, Pluglet = plugletChild, Value = segmentDetails[segmentNum], /*SequenceNumber = segmentSeqNumber, * StartOffset = currentSegmentFieldStartIndex, * EndOffset = currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length,*/ }; validateValue = true; } else if (plugletChild.PlugletType == PlugletType.Segment) { if (string.IsNullOrEmpty(segmentDetails[segmentNum]) == false) { string segmentError = string.Empty; string [] internalSegmentDetails = segmentDetails[segmentNum].Split((char)ediDelimiters.ComponentSeperator); dataFragment = plugletChild.ConstructDocumentFragment(internalSegmentDetails, true, ediDelimiters, segmentSeqNumber, currentSegmentFieldStartIndex, currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length, ref ediErrors, out segmentError); if (string.IsNullOrEmpty(segmentError) == false) { if (string.IsNullOrEmpty(error) == true) { error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name); } error = string.Format("{0} Error constructing {1}: {2}", error, plugletChild.Name, segmentError); } } else { dataFragment = new DocumentFragment() { Parent = documentFragment, Pluglet = plugletChild, Value = segmentDetails[segmentNum], }; } } else { error = string.Format("ConstructDocumentSegmentInstance: Error constructing SegmentInstance. Pluglet {0} is of type {1}", pluglet.Name, plugletChild.Name); return(null); } if (validateValue == true && plugletChild.DataType != null && string.IsNullOrEmpty(segmentDetails[segmentNum]) == false) { FieldError fieldError = plugletChild.DataType.ValidateValue(new StringBuilder(segmentDetails[segmentNum])); if (fieldError != null) { if (string.IsNullOrEmpty(error) == true) { error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name); } error = string.Format("{0} Error data validation failed {1}: {2} ({3})", error, plugletChild.Name, fieldError.Description, fieldError.DataValue); ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, fieldError.ErrorCode, fieldError.Description, segmentSeqNumber, segmentNum, segmentDetails[segmentNum], currentSegmentFieldStartIndex, currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length - 1, errorType); } } //TODO: Add validation (extension method) documentFragment.Children.Add(dataFragment); if (string.IsNullOrEmpty(segmentDetails[segmentNum]) && plugletChild.IsMandatory == true) { if (string.IsNullOrEmpty(error) == true) { error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name); } error = string.Format("{0} Child {1} is mandatory but missing", error, plugletChild.Name); ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, X12ErrorCode.DeMandatoryDataElementMissingCode, X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryDataElementMissingCode), segmentSeqNumber, segmentNum, string.Empty, currentSegmentFieldStartIndex, currentSegmentFieldStartIndex, errorType); } } for (; segmentNum <= pluglet.Children.Count; segmentNum++, plugletNum++) { plugletChild = pluglet.Children[plugletNum]; if (plugletChild.IsMandatory == true) { if (string.IsNullOrEmpty(error) == true) { error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name); } error = string.Format("{0} Child {1} is mandatory but missing", error, plugletChild.Name); ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, X12ErrorCode.DeMandatoryDataElementMissingCode, X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryDataElementMissingCode), segmentSeqNumber, segmentNum, string.Empty, currentSegmentFieldStartIndex, currentSegmentFieldStartIndex, errorType); } } return(documentFragment); }
/// <summary> /// Traverse tree from DocumentFragment based on given xPath. If node is not present /// then add it. /// </summary> /// <param name="currentDocument"></param> /// <param name="xPath"></param> public static DocumentFragment AddIntermediateDocumentFragment(this DocumentFragment document, string xPath) { if (document == null) { throw new ArgumentNullException("document", "AddIntermediateDocumentFragment: Cannot add intermediate document fragments to null DocumentFragment"); } if (string.IsNullOrEmpty(xPath)) { throw new ArgumentNullException("xPath", "AddIntermediateDocumentFragment: xPath cannot be null"); } ILogger logger = LoggerFactory.Logger; string[] pathElements = xPath.Split(new string[] { document.Pluglet.PathSeperator }, StringSplitOptions.None); // Check if root element and 1st element in path match if (string.Equals(pathElements[0], document.Name, StringComparison.OrdinalIgnoreCase) == false) { throw new PlugDataModelException( string.Format("Error while adding intermediate in {0} path. First element in path {1} does not match with root element {2} of document", xPath, pathElements[0], document.Name)); } DocumentFragment nextFragment = null; DocumentFragment currentFragment = (DocumentFragment)document; StringBuilder pathTillCurrentNode = new StringBuilder(); pathTillCurrentNode.AppendFormat("{0}", pathElements[0]); for (int i = 1; i < pathElements.Length - 1; i++) { //TODO: Optimize here - following call is not required once following if condition becomes true if (currentFragment.Children != null) { // Check if it's last child is pathElements[i], otherwise create new instance nextFragment = (DocumentFragment)currentFragment.Children.Last(); if (string.Equals(nextFragment.Name, pathElements[i], StringComparison.OrdinalIgnoreCase) == false) { nextFragment = null; } // Special case for last but one pathElement - Check if we need to recreate node (loop?) // This is required to generate different loop nodes (e.g. BVT_X12_850.txt) if (nextFragment != null && nextFragment.Children != null && i == pathElements.Length - 2 && nextFragment.Pluglet.IsRepeatable == true) { // Check last child and pathElements[i+1] child order DocumentFragment lastChildFragment = (DocumentFragment)nextFragment.Children.Last(); bool restartLoop = false; foreach (IPluglet child in nextFragment.Pluglet.Children) { if (string.Equals(child.Name, pathElements[i + 1], StringComparison.OrdinalIgnoreCase) == true) { restartLoop = true; break; } if (string.Equals(child.Name, lastChildFragment.Name, StringComparison.OrdinalIgnoreCase) == true) { break; } } if (restartLoop == true) { nextFragment = null; } } } pathTillCurrentNode.AppendFormat("{0}{1}", document.Pluglet.PathSeperator, pathElements[i]); if (nextFragment == null) { logger.Debug("DocumentFragmentExtensions.AddDocumentFragment", "Node {0} does not exist, creating one now", currentFragment.Name); IPluglet pluglet = document.Pluglet.MoveTo(pathTillCurrentNode.ToString()); nextFragment = pluglet.ConstructDocumentFragment(currentFragment, null); if (currentFragment.Children == null) { currentFragment.Children = new List <IDocumentFragment>(); } currentFragment.Children.Add(nextFragment); } currentFragment = nextFragment; nextFragment = null; } return(currentFragment); }