/// <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); }
/// <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); }
public static IFatpipeDocument Transform(IFatpipeDocument sourceDocument, ITransformPlug transformPlug) { if (sourceDocument == null) { throw new ArgumentNullException("sourceDocument"); } Stopwatch sw = new Stopwatch(); sw.Start(); FatpipeDocument targetDocument = new FatpipeDocument(); targetDocument.RootFragment = transformPlug.TargetDocument.RootPluglet.ConstructDocumentFragment(null, null);; //TODO: Handle loops foreach (ITransformGroup transformGroup in transformPlug.Facets) { Logger.Debug("DocumentTransformer.Transform", "Processing {0} tranformGroup", transformGroup.Name); foreach (ITransformLink transformLink in transformGroup.Links) { Logger.Debug("DocumentTransformer.Transform", "Processing Link#-{0}: {1} [{2}] => {3} [{4}]" , transformLink.Name , transformLink.Source.ReferenceType, transformLink.Source.Name , transformLink.Target.ReferenceType, transformLink.Target.Name); //TODO: Handle all kind of transformation if (transformLink.Source.ReferenceType == ReferenceType.Document && transformLink.Target.ReferenceType == ReferenceType.Document) { // Traverse source path IDocumentFragment sourceFragment = sourceDocument.RootFragment.MoveTo(transformLink.Source.Name); if (sourceFragment != null) { IPluglet targetPluglet = targetDocument.RootFragment.Pluglet.MoveTo(transformLink.Target.Name); if (targetPluglet != null) { Logger.Debug("DocumentTransformer.Transform", "Source = {0}, Target = {1}", sourceFragment.Name, targetPluglet.Tag); Dictionary <string, string> attributes = new Dictionary <string, string>(); foreach (IPluglet attr in targetPluglet.Attributes) { string attributeName = attr.Name; attributeName.Remove(0, 1); attributeName.Remove(attributeName.Length, 1); attributes.Add(attributeName, attributeName); } bool isAttribute = false; string name = transformLink.Target.Name.Substring( transformLink.Target.Name.LastIndexOf(targetPluglet.PathSeperator) + targetPluglet.PathSeperator.Length); // Check if this transformation point to attribute or leaf node if (targetPluglet.Attributes != null && attributes.ContainsKey(name)) { isAttribute = true; } if (isAttribute == false) { IDocumentFragment newFragment = targetPluglet.ConstructDocumentFragment(null, sourceFragment.Value); ((DocumentFragment)targetDocument.RootFragment).AddDocumentFragment(newFragment); } else { ((DocumentFragment)targetDocument.RootFragment).AddDocumentFragment(transformLink.Target.Name, sourceFragment.Value); } } else { string error = string.Format("Link#-{0}: {1} path not found in target tree", transformLink.Name, transformLink.Target.Name); if (targetDocument.Errors == null) { targetDocument.Errors = new List <string>(); } targetDocument.Errors.Add(error); Logger.Error("DocumentTransformer.Transform", EventId.DocTransformerNoMapping, error); } } } else { Logger.Debug("DocumentTransformer.Transform", "Ignoring Link#-{0}", transformLink.Name); } } //TODO: Handle transformGroup.Formulas } sw.Stop(); Logger.Debug("DocumentTransformer.Transform", "Stop. Elapsed time {0} ms", sw.ElapsedMilliseconds); return(targetDocument); }