コード例 #1
0
ファイル: PathStep.cs プロジェクト: blushingpenguin/Jolt.Net
 public PathStep(JToken treeRef, MatchedElement matchedElement)
 {
     TreeRef        = treeRef;
     MatchedElement = matchedElement;
     if (MatchedElement is ArrayMatchedElement ame)
     {
         OrigSize = ame.GetOrigSize();
     }
 }
コード例 #2
0
        /**
         * This should only be used by composite specs with an '@' child
         *
         * @return null if no work was done, otherwise returns the re-parented data
         */
        public JToken ApplyToParentContainer(string inputKey, JToken input, WalkedPath walkedPath, JToken parentContainer)
        {
            MatchedElement thisLevel = GetMatch(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(null);
            }
            return(PerformCardinalityAdjustment(inputKey, input, walkedPath, (JObject)parentContainer, thisLevel));
        }
コード例 #3
0
        /**
         * If this CardinalitySpec matches the inputkey, then do the work of modifying the data and return true.
         *
         * @return true if this this spec "handles" the inputkey such that no sibling specs need to see it
         */
        public override bool ApplyCardinality(string inputKey, JToken input, WalkedPath walkedPath, JToken parentContainer)
        {
            MatchedElement thisLevel = GetMatch(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(false);
            }
            PerformCardinalityAdjustment(inputKey, input, walkedPath, (JObject)parentContainer, thisLevel);
            return(true);
        }
コード例 #4
0
        public JToken Transform(JToken input, JObject context)
        {
            var contextWrapper = new JObject();

            contextWrapper.Add(ROOT_KEY, context);

            MatchedElement rootLpe    = new MatchedElement(ROOT_KEY);
            WalkedPath     walkedPath = new WalkedPath();

            walkedPath.Add(input, rootLpe);

            _rootSpec.Apply(ROOT_KEY, input, walkedPath, null, contextWrapper);
            return(input);
        }
コード例 #5
0
ファイル: Shiftr.cs プロジェクト: blushingpenguin/Jolt.Net
        /**
         * Applies the Shiftr transform.
         *
         * @param input the JSON object to transform
         * @return the output object with data shifted to it
         * @throws com.bazaarvoice.jolt.exception.TransformException for a malformed spec or if there are issues during
         * the transform
         */
        public JToken Transform(JToken input)
        {
            var output = new JObject();

            // Create a root LiteralPathElement so that # is useful at the root level
            MatchedElement rootLpe    = new MatchedElement(ROOT_KEY);
            WalkedPath     walkedPath = new WalkedPath();

            walkedPath.Add(input, rootLpe);

            _rootSpec.Apply(ROOT_KEY, input, walkedPath, output, null);

            output.TryGetValue(ROOT_KEY, out var result);
            return(result ?? JValue.CreateNull());
        }
コード例 #6
0
        protected override void ApplyElement(string inputKey, JToken inputOptional, MatchedElement thisLevel, WalkedPath walkedPath, JObject context)
        {
            JToken input = inputOptional;

            // sanity checks, cannot work on a list spec with map input and vice versa, and runtime with null input
            if (!_specDataType.IsCompatible(input))
            {
                return;
            }

            // create input if it is null
            if (input == null || input.Type == JTokenType.Null)
            {
                input = _specDataType.Create(inputKey, walkedPath, _opMode);
                // if input has changed, wrap
                if (input != null && input.Type != JTokenType.Null)
                {
                    inputOptional = input;
                }
            }

            // if input is List, create special ArrayMatchedElement, which tracks the original size of the input array
            if (input is JArray list)
            {
                // LIST means spec had array index explicitly specified, hence expand if needed
                if (_specDataType is LIST specList)
                {
                    int?origSize = specList.Expand(input);
                    thisLevel = new ArrayMatchedElement(thisLevel.RawKey, origSize ?? 0);
                }
                else
                {
                    // specDataType is RUNTIME, so spec had no array index explicitly specified, no need to expand
                    thisLevel = new ArrayMatchedElement(thisLevel.RawKey, list.Count);
                }
            }

            // add self to walked path
            walkedPath.Add(input, thisLevel);
            // Handle the rest of the children
            _executionStrategy.Process(this, inputOptional, walkedPath, null, context);
            // We are done, so remove ourselves from the walkedPath
            walkedPath.RemoveLast();
        }
コード例 #7
0
 /**
  * Static utility method for facilitating writes on input object
  *
  * @param parent the source object
  * @param matchedElement the current spec (leaf) element that was matched with input
  * @param value to write
  * @param opMode to determine if write is applicable
  */
 protected static void SetData(JToken parent, MatchedElement matchedElement, JToken value, OpMode opMode)
 {
     if (parent is JObject source)
     {
         string key = matchedElement.RawKey;
         if (opMode.IsApplicable(source, key))
         {
             source[key] = value;
         }
     }
     else if (parent is JArray list && matchedElement is ArrayMatchedElement ame)
     {
         int origSize = ame.GetOrigSize();
         int reqIndex = ame.GetRawIndex();
         if (opMode.IsApplicable(list, reqIndex, origSize))
         {
             list[reqIndex] = value;
         }
     }
コード例 #8
0
        /**
         * If this Spec matches the inputKey, then perform one step in the Shiftr parallel treewalk.
         *
         * Step one level down the input "tree" by carefully handling the List/Map nature the input to
         *  get the "one level down" data.
         *
         * Step one level down the Spec tree by carefully and efficiently applying our children to the
         *  "one level down" data.
         *
         * @return true if this this spec "handles" the inputKey such that no sibling specs need to see it
         */
        public override bool Apply(string inputKey, JToken inputOptional, WalkedPath walkedPath, JObject output, JObject context)
        {
            MatchedElement thisLevel = _pathElement.Match(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(false);
            }

            // If we are a TransposePathElement, try to swap the "input" with what we lookup from the Transpose
            if (_pathElement is TransposePathElement tpe)
            {
                // Note the data found may not be a string, thus we have to call the special objectEvaluate
                // Optional, because the input data could have been a valid null.
                var optional = tpe.ObjectEvaluate(walkedPath);
                if (optional == null)
                {
                    return(false);
                }
                inputOptional = optional;
            }

            // add ourselves to the path, so that our children can reference us
            walkedPath.Add(inputOptional, thisLevel);

            // Handle any special / key based children first, but don't have them block anything
            foreach (ShiftrSpec subSpec in _specialChildren)
            {
                subSpec.Apply(inputKey, inputOptional, walkedPath, output, context);
            }

            // Handle the rest of the children
            _executionStrategy.Process(this, inputOptional, walkedPath, output, context);

            // We are done, so remove ourselves from the walkedPath
            walkedPath.RemoveLast();

            // we matched so increment the matchCount of our parent
            walkedPath.LastElement().MatchedElement.IncrementHashCount();
            return(true);
        }
コード例 #9
0
        public string Evaluate(WalkedPath walkedPath)
        {
            switch (_arrayPathType)
            {
            case ArrayPathType.AUTO_EXPAND:
                return(_canonicalForm);

            case ArrayPathType.EXPLICIT_INDEX:
                return(_arrayIndex);

            case ArrayPathType.HASH:
                MatchedElement element = walkedPath.ElementFromEnd(_ref.GetPathIndex()).MatchedElement;
                return(element.GetHashCount().ToString());

            case ArrayPathType.TRANSPOSE:
                string key = _transposePathElement.Evaluate(walkedPath);
                return(VerifyStringIsNonNegativeInteger(key));

            case ArrayPathType.REFERENCE:
            {
                MatchedElement lpe = walkedPath.ElementFromEnd(_ref.GetPathIndex()).MatchedElement;
                string         keyPart;

                if (_ref is IPathAndGroupReference pagr)
                {
                    keyPart = lpe.GetSubKeyRef(pagr.GetKeyGroup());
                }
                else
                {
                    keyPart = lpe.GetSubKeyRef(0);
                }

                return(VerifyStringIsNonNegativeInteger(keyPart));
            }

            default:
                throw new InvalidOperationException("ArrayPathType enum added two without updating this switch statement.");
            }
        }
コード例 #10
0
        public string Evaluate(WalkedPath walkedPath)
        {
            // Walk thru our tokens and build up a string
            // Use the supplied Path to fill in our token References
            StringBuilder output = new StringBuilder();

            foreach (object token in _tokens)
            {
                if (token is string stoken)
                {
                    output.Append(stoken);
                }
                else
                {
                    AmpReference   ref_           = (AmpReference)token;
                    MatchedElement matchedElement = walkedPath.ElementFromEnd(ref_.GetPathIndex()).MatchedElement;
                    string         value          = matchedElement.GetSubKeyRef(ref_.GetKeyGroup());
                    output.Append(value);
                }
            }

            return(output.ToString());
        }
コード例 #11
0
        /**
         * If this Spec matches the inputkey, then perform one step in the parallel treewalk.
         * <p/>
         * Step one level down the input "tree" by carefully handling the List/Map nature the input to
         * get the "one level down" data.
         * <p/>
         * Step one level down the Spec tree by carefully and efficiently applying our children to the
         * "one level down" data.
         *
         * @return true if this this spec "handles" the inputkey such that no sibling specs need to see it
         */
        public override bool ApplyCardinality(string inputKey, JToken input, WalkedPath walkedPath, JToken parentContainer)
        {
            MatchedElement thisLevel = GetPathElement().Match(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(false);
            }

            walkedPath.Add(input, thisLevel);

            // The specialChild can change the data object that I point to.
            // Aka, my key had a value that was a List, and that gets changed so that my key points to a ONE value
            if (_specialChild != null)
            {
                input = _specialChild.ApplyToParentContainer(inputKey, input, walkedPath, parentContainer);
            }

            // Handle the rest of the children
            Process(input, walkedPath);

            walkedPath.RemoveLast();
            return(true);
        }
コード例 #12
0
        public bool Apply(string inputKey, JToken inputOptional, WalkedPath walkedPath, JObject output, JObject context)
        {
            if (output != null)
            {
                throw new TransformException("Expected a null output");
            }

            MatchedElement thisLevel = _pathElement.Match(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(false);
            }

            if (!_checkValue) // there was no trailing "?" so no check is necessary
            {
                ApplyElement(inputKey, inputOptional, thisLevel, walkedPath, context);
            }
            else if (inputOptional != null)
            {
                ApplyElement(inputKey, inputOptional, thisLevel, walkedPath, context);
            }
            return(true);
        }
コード例 #13
0
        /**
         * If this Spec matches the inputkey, then do the work of outputting data and return true.
         *
         * @return true if this this spec "handles" the inputkey such that no sibling specs need to see it
         */
        public override bool Apply(string inputKey, JToken inputOptional, WalkedPath walkedPath, JObject output, JObject context)
        {
            JToken         input     = inputOptional;
            MatchedElement thisLevel = _pathElement.Match(inputKey, walkedPath);

            if (thisLevel == null)
            {
                return(false);
            }

            JToken data;
            bool   realChild = false; // by default don't block further Shiftr matches

            if (_pathElement is DollarPathElement ||
                _pathElement is HashPathElement)
            {
                // The data is already encoded in the thisLevel object created by the pathElement.match called above
                data = thisLevel.GetCanonicalForm();
            }
            else if (_pathElement is AtPathElement)
            {
                // The data is our parent's data
                data = input;
            }
            else if (_pathElement is TransposePathElement tpe)
            {
                // We try to walk down the tree to find the value / data we want

                // Note the data found may not be a string, thus we have to call the special objectEvaluate
                var evaledData = tpe.ObjectEvaluate(walkedPath);
                if (evaledData != null)
                {
                    data = evaledData;
                }
                else
                {
                    // if we could not find the value we want looking down the tree, bail
                    return(false);
                }
            }
            else
            {
                // the data is the input
                data = input;
                // tell our parent that we matched and no further processing for this inputKey should be done
                realChild = true;
            }

            // Add our the LiteralPathElement for this level, so that write path References can use it as &(0,0)
            walkedPath.Add(input, thisLevel);

            // Write out the data
            foreach (PathEvaluatingTraversal outputPath in _shiftrWriters)
            {
                outputPath.Write(data, output, walkedPath);
            }

            walkedPath.RemoveLast();

            if (realChild)
            {
                // we were a "real" child, so increment the matchCount of our parent
                walkedPath.LastElement().MatchedElement.IncrementHashCount();
            }

            return(realChild);
        }
コード例 #14
0
        /**
         *
         * @return null if no work was done, otherwise returns the re-parented data
         */
        private JToken PerformCardinalityAdjustment(string inputKey, JToken input, WalkedPath walkedPath, JObject parentContainer, MatchedElement thisLevel)
        {
            // Add our the LiteralPathElement for this level, so that write path References can use it as &(0,0)
            walkedPath.Add(input, thisLevel);

            JToken returnValue = null;

            if (_cardinalityRelationship == CardinalityRelationship.MANY)
            {
                if (input is JArray)
                {
                    returnValue = input;
                }
                else if (input.Type == JTokenType.Object || input.Type == JTokenType.String ||
                         input.Type == JTokenType.Integer || input.Type == JTokenType.Float ||
                         input.Type == JTokenType.Boolean)
                {
                    var one = parentContainer[inputKey];
                    parentContainer.Remove(inputKey);
                    var tempList = new JArray();
                    tempList.Add(one);
                    returnValue = tempList;
                }
                else if (input.Type == JTokenType.Null)
                {
                    returnValue = new JArray();
                }
                parentContainer[inputKey] = returnValue;
            }
            else if (_cardinalityRelationship == CardinalityRelationship.ONE)
            {
                if (input is JArray l)
                {
                    // The value is first removed from the array in order to prevent it
                    // from being cloned (JContainers clone their inputs if they are already
                    // part of an object graph)
                    if (l.Count > 0)
                    {
                        returnValue = l[0];
                        l.RemoveAt(0);
                    }
                    parentContainer[inputKey] = returnValue;
                }
            }

            walkedPath.RemoveLast();

            return(returnValue);
        }
コード例 #15
0
 /**
  * Templatr specific override that is used in BaseSpec#apply(...)
  * The name is changed for easy identification during debugging
  */
 protected abstract void ApplyElement(string key, JToken inputOptional, MatchedElement thisLevel, WalkedPath walkedPath, JObject context);