/// <inheritdoc/> internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } JToken transformValue; if (transform.TryGetValue(this.FullVerb, out transformValue)) { if (!this.Transform(source, transformValue, logger)) { // If the transformation returns false, // it performed an operation that halts transforms return; } } this.Successor.Process(source, transform, logger); }
/// <inheritdoc/> internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } foreach (JProperty transformNode in transform.Properties() .Where(p => JdtUtilities.IsJdtSyntax(p.Name))) { string verb = JdtUtilities.GetJdtSyntax(transformNode.Name); if (verb != null) { if (!this.ValidVerbs.Contains(verb)) { throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidVerb, verb), ErrorLocation.Transform, transformNode); } } } this.Successor.Process(source, transform, logger); }
/// <summary> /// Initializes a new instance of the <see cref="JsonTransformation"/> class with an external logger. /// </summary> /// <param name="transform">The stream containing the JSON that specifies the transformation</param> /// /// <param name="logger">The external logger</param> public JsonTransformation(Stream transform, IJsonTransformationLogger logger) { if (transform == null) { throw new ArgumentNullException(nameof(transform)); } this.logger = new JsonTransformationContextLogger(logger); this.SetTransform(transform); }
/// <summary> /// Initializes a new instance of the <see cref="JsonTransformation"/> class with an external logger. /// </summary> /// <param name="transformFile">The path to the file that specifies the transformation</param> /// <param name="logger">The external logger</param> public JsonTransformation(string transformFile, IJsonTransformationLogger logger) { if (string.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException(nameof(transformFile)); } this.logger = new JsonTransformationContextLogger(transformFile, logger); using (FileStream transformStream = File.Open(transformFile, FileMode.Open)) { this.SetTransform(transformStream); } }
public void Start(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } this.processors.First().Process(source, transform, logger); }
/// <summary> /// Executes the entire transformation with the given objects /// Mutates the source object /// </summary> /// <param name="source">Object to be transformed</param> /// <param name="transform">Object that specifies the transformation</param> /// <param name="logger">The logger for the transformation</param> internal static void ProcessTransform(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } // Passes in a clone of the transform object because it can be altered during the transformation process ProcessorChain.Start(source, (JObject)transform.CloneWithLineInfo(), logger); }
private bool RemoveThisNode(JObject nodeToRemove, JsonTransformationContextLogger logger) { var parent = (JProperty)nodeToRemove.Parent; if (parent == null) { // If the node can't be removed, log a warning pointing to the node in the source logger.LogWarning(Resources.WarningMessage_UnableToRemove, ErrorLocation.Source, nodeToRemove); return(true); } else { // If the node is removed, transformations should be halted parent.Value = null; return(false); } }
/// <inheritdoc/> internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } // JDT Verbs are not handled here foreach (JProperty transformNode in transform.Properties() .Where(p => !JdtUtilities.IsJdtSyntax(p.Name))) { JToken nodeToTransform; if (source.TryGetValue(transformNode.Name, out nodeToTransform)) { // If the node is present in both transform and source, analyze the types // If both are objects, that is a recursive transformation, not handled here if (nodeToTransform.Type == JTokenType.Array && transformNode.Value.Type == JTokenType.Array) { // If the original and transform are arrays, merge the contents together ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); } else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) { // TO DO: Verify if object has JDT verbs. They shouldn't be allowed here because they won't be processed // If the contents are different, execute the replace source[transformNode.Name] = transformNode.Value.DeepClone(); } } else { // If the node is not present in the original, add it source.Add(transformNode.DeepClone()); } } this.Successor.Process(source, transform, logger); }
/// <inheritdoc/> protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Object) { // If the value is an object, analyze the contents and perform the appropriate transform return(this.ReplaceWithProperties(source, (JObject)transformValue, logger)); } else { if (source.Root.Equals(source)) { // If trying to replace the root with a non-object token, throw throw JdtException.FromLineInfo(Resources.ErrorMessage_ReplaceRoot, ErrorLocation.Transform, transformValue); } // If the value is not an object, simply replace the original node with the new value source.Replace(transformValue); // If the node is replaced, stop transformations on it return(false); } }
/// <inheritdoc/> protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) { switch (transformValue.Type) { case JTokenType.String: // If the value is just a string, remove that node if (!source.Remove(transformValue.ToString())) { logger.LogWarning(Resources.WarningMessage_UnableToRemove, ErrorLocation.Transform, transformValue); } break; case JTokenType.Boolean: if ((bool)transformValue) { if (source.Root.Equals(source)) { throw JdtException.FromLineInfo(Resources.ErrorMessage_RemoveRoot, ErrorLocation.Transform, transformValue); } // If the transform value is true, remove the entire node return(this.RemoveThisNode(source, logger)); } break; case JTokenType.Object: // If the value is an object, verify the attributes within and perform the remove return(this.RemoveWithAttributes(source, (JObject)transformValue, logger)); default: throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidRemoveValue, transformValue.Type.ToString()), ErrorLocation.Transform, transformValue); } // If nothing indicates a halt, continue with transforms return(true); }
/// <inheritdoc/> protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Object) { // If both source and transform are objects, // analyze the contents and perform the appropriate transforms this.MergeWithObject(source, (JObject)transformValue, logger); } else { // If the transformation is trying to replace the root, throw if (source.Root.Equals(source)) { throw JdtException.FromLineInfo(Resources.ErrorMessage_ReplaceRoot, ErrorLocation.Transform, transformValue); } // If the transform value is not an object, then simply replace it with the new token source.Replace(transformValue); } // Do not halt transformations return(true); }
/// <inheritdoc/> internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (transform == null) { throw new ArgumentNullException(nameof(transform)); } // Nodes that should be removed from the transform after they are handled var nodesToRemove = new List <string>(); foreach (JProperty transformNode in transform.Properties() .Where(p => p.Value.Type == JTokenType.Object && !JdtUtilities.IsJdtSyntax(p.Name))) { // We recurse into objects that do not correspond to JDT verbs and that exist in both source and transform JToken sourceChild; if (source.TryGetValue(transformNode.Name, out sourceChild) && sourceChild.Type == JTokenType.Object) { ProcessTransform((JObject)sourceChild, (JObject)transformNode.Value, logger); // If we have already recursed into that node, it should be removed from the transform nodesToRemove.Add(transformNode.Name); } } // Remove all of the previously handled nodes // This is necessary so that a rename does not cause a node to be hadled twice nodesToRemove.ForEach(node => transform.Remove(node)); // Continue to next transformation this.Successor.Process(source, transform, logger); }
/// <summary> /// Performs the initial logic of processing arrays. /// Arrays cause the transform to be applied to each value in them /// </summary> /// <param name="source">Object to be transformed</param> /// <param name="transformValue">Value of the transform</param> /// <param name="logger">The transformation context logger</param> /// <returns>True if transforms should continue</returns> private bool Transform(JObject source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Array) { // If the value is an array, perform the transformation for each object in the array // From here, arrays are handled as the transformation value foreach (JToken arrayValue in (JArray)transformValue) { if (!this.ProcessCore(source, arrayValue, logger)) { // If the core transformation indicates a halt, we halt return(true); } } // If we are not told to stop, we continue with transformations return(true); } else { // If it is not an array, perform the transformation as normal return(this.ProcessCore(source, transformValue, logger)); } }
/// <summary> /// The core transformation logic. Arrays are treated as the transform values /// </summary> /// <param name="source">Object to be transformed</param> /// <param name="transformValue">Value of the transform</param> /// <param name="logger">The transformation context logger</param> /// <returns>True if transforms should continue</returns> protected abstract bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger);
private bool RemoveWithAttributes(JObject source, JObject removeObject, JsonTransformationContextLogger logger) { var attributes = this.attributeValidator.ValidateAndReturnAttributes(removeObject); // The remove attribute only accepts objects if they have only the path attribute JToken pathToken; if (attributes.TryGetValue(JdtAttributes.Path, out pathToken)) { if (pathToken.Type == JTokenType.String) { var tokensToRemove = source.SelectTokens(pathToken.ToString()).ToList(); if (!tokensToRemove.Any()) { logger.LogWarning(Resources.WarningMessage_NoResults, ErrorLocation.Transform, pathToken); } // Removes all of the tokens specified by the path foreach (JToken token in tokensToRemove) { if (token.Equals(source)) { if (source.Root.Equals(source)) { throw JdtException.FromLineInfo(Resources.ErrorMessage_RemoveRoot, ErrorLocation.Transform, removeObject); } // If the path specifies the current node if (!this.RemoveThisNode(source, logger)) { // Halt transformations return(false); } } else { if (token.Parent.Type == JTokenType.Property) { // If the token is the value of a property, // the property must be removed token.Parent.Remove(); } else { // If the token is a property or an element in an array, // it must be removed directly token.Remove(); } } } } else { throw JdtException.FromLineInfo(Resources.ErrorMessage_PathContents, ErrorLocation.Transform, pathToken); } } else { throw JdtException.FromLineInfo(Resources.ErrorMessage_RemoveAttributes, ErrorLocation.Transform, removeObject); } // If nothing indicates a halt, continue transforms return(true); }
private bool ReplaceWithProperties(JObject source, JObject replaceObject, JsonTransformationContextLogger logger) { var attributes = this.attributeValidator.ValidateAndReturnAttributes(replaceObject); // If there are attributes, handle them accordingly if (attributes.Any()) { // If the object has attributes it must have both path and value JToken pathToken, valueToken; if (attributes.TryGetValue(JdtAttributes.Path, out pathToken) && attributes.TryGetValue(JdtAttributes.Value, out valueToken)) { if (pathToken.Type != JTokenType.String) { throw JdtException.FromLineInfo(Resources.ErrorMessage_PathContents, ErrorLocation.Transform, pathToken); } var tokensToReplace = source.SelectTokens(pathToken.ToString()).ToList(); if (!tokensToReplace.Any()) { logger.LogWarning(Resources.WarningMessage_NoResults, ErrorLocation.Transform, pathToken); } foreach (JToken token in tokensToReplace) { bool replacedThisNode = false; if (token.Root.Equals(token) && valueToken.Type != JTokenType.Object) { // If trying to replace the root object with a token that is not another object, throw throw JdtException.FromLineInfo(Resources.ErrorMessage_ReplaceRoot, ErrorLocation.Transform, pathToken); } if (token.Equals(source)) { // If the specified path is to the current node replacedThisNode = true; } token.Replace(valueToken); if (replacedThisNode) { // If the current node was replaced, stop executing transformations on this node return(false); } } } else { // If either is not present, throw throw JdtException.FromLineInfo(Resources.ErrorMessage_ReplaceAttributes, ErrorLocation.Transform, replaceObject); } // If we got here, transformations should continue return(true); } else { // If there are no attributes, replace the current object with the given object // Here, the root can be replaced as the replace value is an object source.Replace(replaceObject); // If the node is replaced, stop transformations on it return(false); } }
private void MergeWithObject(JObject source, JObject mergeObject, JsonTransformationContextLogger logger) { var attributes = this.attributeValidator.ValidateAndReturnAttributes(mergeObject); // If there are attributes, handle them accordingly if (attributes.Any()) { // If the object has attributes it must have both path and value // TO DO: Accept value without path JToken pathToken, valueToken; if (attributes.TryGetValue(JdtAttributes.Path, out pathToken) && attributes.TryGetValue(JdtAttributes.Value, out valueToken)) { if (pathToken.Type != JTokenType.String) { throw JdtException.FromLineInfo(Resources.ErrorMessage_PathContents, ErrorLocation.Transform, mergeObject); } var tokensToMerge = source.SelectTokens(pathToken.ToString()).ToList(); if (!tokensToMerge.Any()) { logger.LogWarning(Resources.WarningMessage_NoResults, ErrorLocation.Transform, pathToken); } foreach (JToken token in tokensToMerge) { // Perform the merge for each element found through the path if (token.Type == JTokenType.Object && valueToken.Type == JTokenType.Object) { // If they are both objects, start a new transformation ProcessTransform((JObject)token, (JObject)valueToken, logger); } else if (token.Type == JTokenType.Array && valueToken.Type == JTokenType.Array) { // If they are both arrays, add the new values to the original ((JArray)token).Merge(valueToken.DeepClone()); } else { // If the transformation is trying to replace the root, throw if (token.Root.Equals(token)) { throw JdtException.FromLineInfo(Resources.ErrorMessage_ReplaceRoot, ErrorLocation.Transform, mergeObject); } // If they are primitives or have different values, perform a replace token.Replace(valueToken); } } } else { // If either is not present, throw throw JdtException.FromLineInfo(Resources.ErrorMessage_MergeAttributes, ErrorLocation.Transform, mergeObject); } } else { // If the merge object does not contain attributes, // simply execute the transform with that object ProcessTransform(source, mergeObject, logger); } }
internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) { // Do nothing, the chain is done }
/// <summary> /// Executes the transformation /// </summary> /// <param name="source">Object to be transformed</param> /// <param name="transform">Object specifying the transformation</param> /// <param name="logger">The logger for the transformation</param> internal abstract void Process(JObject source, JObject transform, JsonTransformationContextLogger logger);
/// <inheritdoc/> protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type != JTokenType.Object) { // Rename only accepts objects, either with properties or direct renames throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidRenameValue, transformValue.Type.ToString()), ErrorLocation.Transform, transformValue); } else { // Try and get attributes from the object var renameObject = (JObject)transformValue; var attributes = this.attributeValidator.ValidateAndReturnAttributes(renameObject); // If there are attributes, handle them accordingly if (attributes.Any()) { // If the object has attributes it must have both path and value JToken pathToken, valueToken; if (attributes.TryGetValue(JdtAttributes.Path, out pathToken) && attributes.TryGetValue(JdtAttributes.Value, out valueToken)) { if (pathToken.Type != JTokenType.String) { throw JdtException.FromLineInfo(Resources.ErrorMessage_PathContents, ErrorLocation.Transform, pathToken); } if (valueToken.Type != JTokenType.String) { throw JdtException.FromLineInfo(Resources.ErrorMessage_ValueContents, ErrorLocation.Transform, valueToken); } var tokensToRename = source.SelectTokens(pathToken.ToString()).ToList(); if (!tokensToRename.Any()) { logger.LogWarning(Resources.WarningMessage_NoResults, ErrorLocation.Transform, pathToken); } // If the values are correct, rename each token found with the given path foreach (JToken token in tokensToRename) { if (!this.RenameNode(token, valueToken.ToString())) { throw JdtException.FromLineInfo(Resources.ErrorMessage_RenameNode, ErrorLocation.Transform, renameObject); } } } else { // If either is not present, throw throw JdtException.FromLineInfo(Resources.ErrorMessage_RenameAttributes, ErrorLocation.Transform, renameObject); } } else { // If the object does not contain attributes, each property is a rename to execute // where the key is the old name and the value must be a string with the new name of the node foreach (JProperty renameOperation in renameObject.Properties()) { if (renameOperation.Value.Type != JTokenType.String) { throw JdtException.FromLineInfo(Resources.ErrorMessage_ValueContents, ErrorLocation.Transform, renameOperation); } // TO DO: Warning if the node is not found JToken nodeToRename; if (source.TryGetValue(renameOperation.Name, out nodeToRename)) { if (!this.RenameNode(nodeToRename, renameOperation.Value.ToString())) { throw JdtException.FromLineInfo(Resources.ErrorMessage_RenameNode, ErrorLocation.Transform, renameOperation); } } else { logger.LogWarning(string.Format(Resources.WarningMessage_NodeNotFound, renameOperation.Name), ErrorLocation.Transform, renameOperation); } } } } // Do not halt transformations return(true); }