/// <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> /// Validates the object and returns the appropriate attributes contained within it. /// Throws if an invalid jdt attribute is found. /// </summary> /// <param name="transformObject">The object to validade</param> /// <returns>A dictionary with the JToken attributes of each valid attribute. /// An empty dictionary is returned if no valid properties are found</returns> internal Dictionary <JdtAttributes, JToken> ValidateAndReturnAttributes(JObject transformObject) { if (transformObject == null) { throw new ArgumentNullException(nameof(transformObject)); } Dictionary <JdtAttributes, JToken> attributes = new Dictionary <JdtAttributes, JToken>(); // First, we look through all of the properties that have JDT syntax foreach (JProperty property in transformObject.GetJdtProperties()) { JdtAttributes attribute = this.validAttributes.GetByName(property.Name); if (attribute == JdtAttributes.None) { // TO DO: Specify the transformation in the error // If the attribute is not supported in this transformation, throw throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidAttribute, property.Name), ErrorLocation.Transform, property); } else { // If it is a valid JDT attribute, add its value to the dictionary attributes.Add(attribute, property.Value); } } // If the object has attributes, it should not have any other properties in it if (attributes.Count > 0 && attributes.Count != transformObject.Properties().Count()) { throw JdtException.FromLineInfo(Resources.ErrorMessage_InvalidAttributes, ErrorLocation.Transform, transformObject); } return(attributes); }
/// <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); } }
/// <summary> /// Logs an error from an internal exception /// </summary> /// <param name="exception">The exception to log</param> internal void LogErrorFromException(Exception exception) { if (exception == null) { throw new ArgumentNullException(nameof(exception)); } // Only log if an external logger has been provided if (this.externalLogger != null) { this.HasLoggedErrors = true; // First, attempt to convert to a JdtException that contains lineinfo and error location JdtException jdtException = exception as JdtException; if (jdtException != null) { this.externalLogger.LogErrorFromException(jdtException, this.LocationPath(jdtException.Location), jdtException.LineNumber, jdtException.LinePosition); } else { // JsonReader exceptions are caused by loading errors and contain file and line info JsonReaderException readerException = exception as JsonReaderException; if (readerException != null) { this.externalLogger.LogErrorFromException(readerException, readerException.Path, readerException.LineNumber, readerException.LinePosition); } else { // If the exception does not have any additional info on it this.externalLogger.LogErrorFromException(exception); } } } else { ExceptionDispatchInfo.Capture(exception).Throw(); } }
/// <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); }
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); }
/// <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); }
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); } }
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); } }