Exemple #1
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);
        }
        /**
         *
         * @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);
        }
Exemple #3
0
        /**
         * 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());
        }
        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();
        }
        /**
         * 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);
        }
Exemple #6
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);
        }
        /**
         * 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);
        }
        public void Apply(JToken input, WalkedPath walkedPath)
        {
            if (input is JArray arr)
            {
                HashSet <int> indexesToRemove = null;

                for (int i = 0; i < arr.Count; ++i)
                {
                    var elt = arr[i];
                    var key = i.ToString();
                    foreach (var child in Children.Values)
                    {
                        var match = child.PathElement.Match(key, walkedPath);
                        if (match == null)
                        {
                            continue;
                        }
                        if (IsFiltered(child, elt))
                        {
                            if (indexesToRemove == null)
                            {
                                indexesToRemove = new HashSet <int>();
                            }
                            indexesToRemove.Add(i);
                        }
                        else
                        {
                            walkedPath.Add(key, match);
                            child.Apply(elt, walkedPath);
                            walkedPath.RemoveLast();
                        }
                    }
                }

                if (indexesToRemove != null)
                {
                    foreach (var index in indexesToRemove.OrderByDescending(x => x))
                    {
                        arr.RemoveAt(index);
                    }
                }
            }
            else if (input is JObject obj)
            {
                HashSet <string> keysToRemove = null;
                foreach (var kv in obj)
                {
                    foreach (var child in Children.Values)
                    {
                        var match = child.PathElement.Match(kv.Key, walkedPath);
                        if (match == null)
                        {
                            continue;
                        }
                        if (IsFiltered(child, kv.Value))
                        {
                            if (keysToRemove == null)
                            {
                                keysToRemove = new HashSet <string>();
                            }
                            keysToRemove.Add(kv.Key);
                        }
                        else
                        {
                            walkedPath.Add(kv.Key, match);
                            child.Apply(kv.Value, walkedPath);
                            walkedPath.RemoveLast();
                        }
                    }
                }
                if (keysToRemove != null)
                {
                    foreach (string key in keysToRemove)
                    {
                        obj.Remove(key);
                    }
                }
            }
        }