Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MappingKey"/> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="path">The path.</param>
        /// <param name="schema">The schema.</param>
        public MappingKey(string key, AttributePath path, ValueSchema schema)
            : this(key)
        {
            if (path != null)
            {
                this.Path = path;
            }

            this.Schema = schema;

            if (this.Schema.IsBlock)
            {
                this.InitialAnalysis =
                    this.Schema.IsListOrSet ? AttributeContent.BlockList : AttributeContent.BlockObject;
            }
            else if (this.Schema.IsListOrSet)
            {
                this.InitialAnalysis = AttributeContent.Sequence;
            }
            else if (this.Schema.IsScalar)
            {
                this.InitialAnalysis = AttributeContent.Value;
            }
            else if (this.Schema.Type == SchemaValueType.TypeMap)
            {
                this.InitialAnalysis = AttributeContent.Mapping;
            }
            else
            {
                this.InitialAnalysis = AttributeContent.None;
            }
        }
        public void ShouldSplitIndexedPath()
        {
            const string Path     = "key1['multi.part.key']";
            var          expected = new[] { "key1", "multi.part.key" };

            AttributePath.Split(Path).Should().BeEquivalentTo(expected);
        }
        /// <summary>
        ///     This method will make an AttributePath for a given an EFObject.
        /// </summary>
        private static AttributePath MakeAttributePathFromEFObject(EFObject efobject)
        {
            var attributePath = new AttributePath();
            var curr          = efobject.XObject;

            while (curr != null)
            {
                if (curr.NodeType == XmlNodeType.Document)
                {
                    var doc = (XDocument)curr;
                    attributePath.PushFront(doc.Root.Name.LocalName, doc.Root.Name.Namespace.NamespaceName, true);
                }
                else if (curr.NodeType == XmlNodeType.Attribute)
                {
                    var attr = (XAttribute)curr;
                    attributePath.PushFront(attr.Name.LocalName, attr.Name.Namespace.NamespaceName, false);
                }
                else if (curr.NodeType == XmlNodeType.Element)
                {
                    var el = (XElement)curr;
                    attributePath.PushFront(el.Name.LocalName, el.Name.Namespace.NamespaceName, true);
                }
                else
                {
                    Debug.Fail("Unexpected XObject type is neither an attribute nor an element");
                    return(null);
                }

                curr = curr.Parent;
            }
            return(attributePath);
        }
            internal AttributePath Clone()
            {
                var clone = new AttributePath();
                var array = _stack.ToArray();

                for (var i = array.Length - 1; i > -1; i--)
                {
                    clone._stack.Push(array[i]);
                }
                return(clone);
            }
 /// <summary>
 ///     Validates a proposed string against a given "path" to a node.
 /// </summary>
 /// <param name="proposedString"></param>
 /// <param name="attributePath"></param>
 /// <returns></returns>
 internal bool IsValidStringForSchemaType(string proposedString, AttributePath attributePath)
 {
     var type = GetTypeNameForNode(attributePath);
     if (type == null)
     {
         Debug.Fail("didn't find XmlSchemaType for given attribute path");
         return false;
     }
     else
     {
         return IsValidStringForSchemaType(proposedString, type.QualifiedName);
     }
 }
        /// <summary>
        ///     Validates a proposed string against a given "path" to a node.
        /// </summary>
        /// <param name="proposedString"></param>
        /// <param name="attributePath"></param>
        /// <returns></returns>
        internal bool IsValidStringForSchemaType(string proposedString, AttributePath attributePath)
        {
            var type = GetTypeNameForNode(attributePath);

            if (type == null)
            {
                Debug.Fail("didn't find XmlSchemaType for given attribute path");
                return(false);
            }
            else
            {
                return(IsValidStringForSchemaType(proposedString, type.QualifiedName));
            }
        }
Example #7
0
        private static LinqExpression GetPathExpression(AttributePath path, LinqExpression representationAttrExpr)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (representationAttrExpr == null)
            {
                throw new ArgumentNullException(nameof(representationAttrExpr));
            }

            var schemaAttributeParameter = LinqExpression.Property(representationAttrExpr, "SchemaAttribute");
            var propertyName             = LinqExpression.Property(schemaAttributeParameter, "Name");
            var notNull = LinqExpression.NotEqual(schemaAttributeParameter, LinqExpression.Constant(null));
            var equal   = LinqExpression.Equal(propertyName, LinqExpression.Constant(path.Name));

            return(LinqExpression.AndAlso(notNull, equal));
        }
        /// <summary>
        ///     This is a convenience method that will create an AttributePath instance from a string of the form "xxx/yyy/zzz/attr".  This assumes that
        ///     "attr" is the name of an attribute with no namespace value, and that "xxx", "yyy" and "zzz" are element names with namespace nameSpaceUri.
        ///     This is a valid assumption for CSDL, SSDL & MSL XSD definitions, but is not necessarily true for all XSDs.
        /// </summary>
        internal static AttributePath MakeAttributePathFromString(string nameSpaceUri, string path)
        {
            var parts         = path.Split('/');
            var attributePath = new AttributePath();

            for (var i = parts.Length - 1; i >= 0; --i)
            {
                // assume that the last one is always an attribute with empty namespace URI.  This is a valid assumption for our csdl/ssdl/msl cases
                if (i == parts.Length - 1)
                {
                    attributePath.PushFront(parts[i], String.Empty, false);
                }
                else
                {
                    attributePath.PushFront(parts[i], nameSpaceUri, true);
                }
            }
            return(attributePath);
        }
Example #9
0
        private static LinqExpression EvaluateSelection(this AttributePath path, LinqExpression outerExpression)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (outerExpression == null)
            {
                throw new ArgumentNullException(nameof(outerExpression));
            }

            var resourceAttrParameterExpr = LinqExpression.Parameter(typeof(RepresentationAttribute), "a");
            var equality          = GetPathExpression(path, resourceAttrParameterExpr);
            var call              = LinqExpression.Lambda <Func <RepresentationAttribute, bool> >(equality, resourceAttrParameterExpr);
            var whereMethod       = GetWhereMethod <RepresentationAttribute>();
            var result            = LinqExpression.Call(whereMethod, outerExpression, call);
            var enumerableType    = typeof(Queryable);
            var enumerableMethods = enumerableType.GetMethods();

            if (path.Next != null)
            {
                var next              = path.Next;
                var outerArg          = LinqExpression.Parameter(typeof(RepresentationAttribute), "x");
                var innerArg          = LinqExpression.Parameter(typeof(RepresentationAttribute), "y");
                var outerProperty     = LinqExpression.Property(outerArg, "Id");
                var innerProperty     = LinqExpression.Property(innerArg, "RepresentationAttributeIdParent");
                var outerLambda       = LinqExpression.Lambda(outerProperty, new System.Linq.Expressions.ParameterExpression[] { outerArg });
                var innerLambda       = LinqExpression.Lambda(innerProperty, new System.Linq.Expressions.ParameterExpression[] { innerArg });
                var resultSelector    = LinqExpression.Lambda(innerArg, new System.Linq.Expressions.ParameterExpression[] { outerArg, innerArg });
                var joinMethod        = enumerableMethods.Where(m => m.Name == "Join" && m.IsGenericMethodDefinition).Where(m => m.GetParameters().ToList().Count == 5).First();
                var joinGenericMethod = joinMethod.MakeGenericMethod(typeof(RepresentationAttribute), typeof(RepresentationAttribute), typeof(string), typeof(RepresentationAttribute));
                result = LinqExpression.Call(joinGenericMethod, result, outerExpression, outerLambda, innerLambda, resultSelector); // add join.
                return(EvaluateSelection(next, result));
            }

            return(result);
        }
Example #10
0
        private static LinqExpression Evaluate(this AttributePath attributePath, System.Linq.Expressions.ParameterExpression resourceAttrParameterExpr)
        {
            if (attributePath == null)
            {
                throw new ArgumentNullException(nameof(attributePath));
            }

            var result = GetPathExpression(attributePath, resourceAttrParameterExpr);

            if (attributePath.ValueFilter != null)
            {
                var anyExpr = BuildChildrenExpr(attributePath.ValueFilter.Expression, resourceAttrParameterExpr);
                result = LinqExpression.AndAlso(result, anyExpr);
            }

            if (attributePath.Next != null)
            {
                var anyExpr = EvaluateChildren(attributePath, resourceAttrParameterExpr, null);
                result = LinqExpression.AndAlso(result, anyExpr);
            }

            return(result);
        }
        /// <summary>
        ///     Returns the XmlSchemaType for the given node.
        /// </summary>
        /// <param name="attributePath"></param>
        /// <returns></returns>
        protected XmlSchemaType GetTypeNameForNode(AttributePath attributePath)
        {
            if (attributePath == null)
            {
                throw new ArgumentNullException("attributePath");
            }

            var attributePathCopy = attributePath.Clone();

            if (attributePathCopy.Count < 1)
            {
                return null;
            }

            // prime the pump.  The first node on the stack should be a global element.
            var curr = attributePathCopy.PopFront();
            var schemaElement = GetXmlSchemaObject(SchemaSet.GlobalElements, curr.qname) as XmlSchemaElement;

            if (schemaElement == null)
            {
                Debug.Fail("Unable to find Global Schema Element " + curr.qname);
                return null;
            }

            var schemaType = GetXmlSchemaTypeFromXmlSchemaElement(schemaElement);

            if (schemaType == null)
            {
                Debug.Fail("Unable to find schema type for schema element " + curr.qname);
                return null;
            }

            while (attributePathCopy.Count > 0)
            {
                curr = attributePathCopy.PopFront();

                var xsct = schemaType as XmlSchemaComplexType;
                if (xsct != null)
                {
                    if (curr.type == AttributePath.QNameNodeTypePair.NodeType.Element)
                    {
                        XmlSchemaElement xe = null;
                        while (xe == null
                               && xsct != null)
                        {
                            xe = GetXmlSchemaElementFromParticle(xsct.Particle, curr.qname);

                            if (xe == null)
                            {
                                // check the content type particle
                                xe = GetXmlSchemaElementFromParticle(xsct.ContentTypeParticle, curr.qname);
                            }

                            if (xe == null)
                            {
                                // check the base type
                                xsct = xsct.BaseXmlSchemaType as XmlSchemaComplexType;
                            }
                        }

                        if (xe == null)
                        {
                            Debug.Fail("didn't find XmlSchemaElement for qname " + curr.qname + " in type " + schemaType.QualifiedName);
                            return null;
                        }
                        else
                        {
                            schemaType = GetXmlSchemaTypeFromXmlSchemaElement(xe);
                        }
                    }
                    else
                    {
                        // we need to find an attribute
                        // see if it is a global attribute first
                        var xa = GetXmlSchemaObject(SchemaSet.GlobalAttributes, curr.qname) as XmlSchemaAttribute;

                        // if that doesn't work try to see whether it's an attribute on the XmlSchemaComplexType xsct
                        if (xa == null)
                        {
                            xa = GetXmlSchemaAttributeFromXmlSchemaGroupBase(xsct, curr.qname);
                        }

                        if (xa == null)
                        {
                            Debug.Fail(
                                "didn't find XmlSchemaAttribute for qname " + curr.qname + " in Global Attributes or in type "
                                + xsct.QualifiedName);
                            return null;
                        }
                        else
                        {
                            schemaType = GetXmlSchemaTypeFromXmlSchemaAttribute(xa);
                        }
                    }
                }
                else
                {
                    Debug.Fail("not yet implemented!");
                }
            }

            return schemaType;
        }
Example #12
0
        private static LinqExpression EvaluateChildren(AttributePath path, System.Linq.Expressions.ParameterExpression arg, Func <System.Linq.Expressions.ParameterExpression, LinqExpression> callback = null)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (arg == null)
            {
                throw new ArgumentNullException(nameof(arg));
            }

            var subArg                    = LinqExpression.Parameter(typeof(RepresentationAttribute), GetSc());
            var subChild                  = LinqExpression.Parameter(typeof(RepresentationAttribute), GetSc());
            var childrenProperty          = LinqExpression.Property(arg, "Children");
            var argChildrenProperty       = LinqExpression.Property(subArg, "Children");
            var schemaAttributeProperty   = LinqExpression.Property(arg, "SchemaAttribute");
            var schemaTypeProperty        = LinqExpression.Property(schemaAttributeProperty, "Type");
            var schemaMultiValuedProperty = LinqExpression.Property(schemaAttributeProperty, "MultiValued");

            var isMultiValued           = LinqExpression.Equal(schemaMultiValuedProperty, LinqExpression.Constant(true)); // true
            var isNotMultiValued        = LinqExpression.Equal(schemaMultiValuedProperty, LinqExpression.Constant(false));
            var isTypeComplex           = LinqExpression.Equal(schemaTypeProperty, LinqExpression.Constant(Common.Constants.SchemaAttributeTypes.Complex));
            var isNotTypeComplex        = LinqExpression.NotEqual(schemaTypeProperty, LinqExpression.Constant(Common.Constants.SchemaAttributeTypes.Complex));
            var isComplexMultiValued    = LinqExpression.AndAlso(isMultiValued, isTypeComplex);
            var isNotComplexMultiValued = LinqExpression.OrElse(isNotTypeComplex, isNotMultiValued);

            var            itemCount    = LinqExpression.Call(typeof(Enumerable), "Count", new[] { typeof(RepresentationAttribute) }, childrenProperty);
            var            moreThanZero = LinqExpression.GreaterThan(itemCount, LinqExpression.Constant(0));
            LinqExpression result       = null;

            if (callback != null)
            {
                result = callback(subChild);
            }

            if (path.Next != null)
            {
                var subCond = path.Next.Evaluate(subChild);
                if (result != null)
                {
                    result = LinqExpression.AndAlso(result, subCond);
                }
                else
                {
                    result = subCond;
                }
            }
            // a => aaze = azeaze
            var callEqualValue = LinqExpression.Lambda <Func <RepresentationAttribute, bool> >(result, subChild); // c => c.value = <value>
            var anyComplexMultiValuedSubAnyExpr = LinqExpression.Call(typeof(Enumerable), _anyMethodName, new[] { typeof(RepresentationAttribute) }, argChildrenProperty, callEqualValue);
            var lambdaMultiValuedSubAnyExpr     = LinqExpression.Lambda <Func <RepresentationAttribute, bool> >(anyComplexMultiValuedSubAnyExpr, subArg);
            var anyComplexMultiValuedAnyExpr    = LinqExpression.Call(typeof(Enumerable), _anyMethodName, new[] { typeof(RepresentationAttribute) }, childrenProperty, lambdaMultiValuedSubAnyExpr);
            var anyNotComplexMultiValuedExpr    = LinqExpression.Call(typeof(Enumerable), _anyMethodName, new[] { typeof(RepresentationAttribute) }, childrenProperty, callEqualValue);
            var firstNotComplexMultiValued      = LinqExpression.AndAlso(isNotComplexMultiValued, moreThanZero);
            var notComplexMultiValued           = LinqExpression.AndAlso(firstNotComplexMultiValued, anyNotComplexMultiValuedExpr);
            var firstComplexMultiValued         = LinqExpression.AndAlso(isComplexMultiValued, moreThanZero);
            var complexMultiValued = LinqExpression.AndAlso(firstComplexMultiValued, anyComplexMultiValuedAnyExpr);

            return(LinqExpression.OrElse(complexMultiValued, notComplexMultiValued));
        }
 internal AttributePath Clone()
 {
     var clone = new AttributePath();
     var array = _stack.ToArray();
     for (var i = array.Length - 1; i > -1; i--)
     {
         clone._stack.Push(array[i]);
     }
     return clone;
 }
        /// <summary>
        ///     This method will make an AttributePath for a given an EFObject.
        /// </summary>
        private static AttributePath MakeAttributePathFromEFObject(EFObject efobject)
        {
            var attributePath = new AttributePath();
            var curr = efobject.XObject;
            while (curr != null)
            {
                if (curr.NodeType == XmlNodeType.Document)
                {
                    var doc = (XDocument)curr;
                    attributePath.PushFront(doc.Root.Name.LocalName, doc.Root.Name.Namespace.NamespaceName, true);
                }
                else if (curr.NodeType == XmlNodeType.Attribute)
                {
                    var attr = (XAttribute)curr;
                    attributePath.PushFront(attr.Name.LocalName, attr.Name.Namespace.NamespaceName, false);
                }
                else if (curr.NodeType == XmlNodeType.Element)
                {
                    var el = (XElement)curr;
                    attributePath.PushFront(el.Name.LocalName, el.Name.Namespace.NamespaceName, true);
                }
                else
                {
                    Debug.Fail("Unexpected XObject type is neither an attribute nor an element");
                    return null;
                }

                curr = curr.Parent;
            }
            return attributePath;
        }
        /// <summary>
        ///     Returns the XmlSchemaType for the given node.
        /// </summary>
        /// <param name="attributePath"></param>
        /// <returns></returns>
        protected XmlSchemaType GetTypeNameForNode(AttributePath attributePath)
        {
            if (attributePath == null)
            {
                throw new ArgumentNullException("attributePath");
            }

            var attributePathCopy = attributePath.Clone();

            if (attributePathCopy.Count < 1)
            {
                return(null);
            }

            // prime the pump.  The first node on the stack should be a global element.
            var curr          = attributePathCopy.PopFront();
            var schemaElement = GetXmlSchemaObject(SchemaSet.GlobalElements, curr.qname) as XmlSchemaElement;

            if (schemaElement == null)
            {
                Debug.Fail("Unable to find Global Schema Element " + curr.qname);
                return(null);
            }

            var schemaType = GetXmlSchemaTypeFromXmlSchemaElement(schemaElement);

            if (schemaType == null)
            {
                Debug.Fail("Unable to find schema type for schema element " + curr.qname);
                return(null);
            }

            while (attributePathCopy.Count > 0)
            {
                curr = attributePathCopy.PopFront();

                var xsct = schemaType as XmlSchemaComplexType;
                if (xsct != null)
                {
                    if (curr.type == AttributePath.QNameNodeTypePair.NodeType.Element)
                    {
                        XmlSchemaElement xe = null;
                        while (xe == null &&
                               xsct != null)
                        {
                            xe = GetXmlSchemaElementFromParticle(xsct.Particle, curr.qname);

                            if (xe == null)
                            {
                                // check the content type particle
                                xe = GetXmlSchemaElementFromParticle(xsct.ContentTypeParticle, curr.qname);
                            }

                            if (xe == null)
                            {
                                // check the base type
                                xsct = xsct.BaseXmlSchemaType as XmlSchemaComplexType;
                            }
                        }

                        if (xe == null)
                        {
                            Debug.Fail("didn't find XmlSchemaElement for qname " + curr.qname + " in type " + schemaType.QualifiedName);
                            return(null);
                        }
                        else
                        {
                            schemaType = GetXmlSchemaTypeFromXmlSchemaElement(xe);
                        }
                    }
                    else
                    {
                        // we need to find an attribute
                        // see if it is a global attribute first
                        var xa = GetXmlSchemaObject(SchemaSet.GlobalAttributes, curr.qname) as XmlSchemaAttribute;

                        // if that doesn't work try to see whether it's an attribute on the XmlSchemaComplexType xsct
                        if (xa == null)
                        {
                            xa = GetXmlSchemaAttributeFromXmlSchemaGroupBase(xsct, curr.qname);
                        }

                        if (xa == null)
                        {
                            Debug.Fail(
                                "didn't find XmlSchemaAttribute for qname " + curr.qname + " in Global Attributes or in type "
                                + xsct.QualifiedName);
                            return(null);
                        }
                        else
                        {
                            schemaType = GetXmlSchemaTypeFromXmlSchemaAttribute(xa);
                        }
                    }
                }
                else
                {
                    Debug.Fail("not yet implemented!");
                }
            }

            return(schemaType);
        }
 /// <summary>
 ///     This is a convenience method that will create an AttributePath instance from a string of the form "xxx/yyy/zzz/attr".  This assumes that
 ///     "attr" is the name of an attribute with no namespace value, and that "xxx", "yyy" and "zzz" are element names with namespace nameSpaceUri.
 ///     This is a valid assumption for CSDL, SSDL & MSL XSD definitions, but is not necessarily true for all XSDs.
 /// </summary>
 internal static AttributePath MakeAttributePathFromString(string nameSpaceUri, string path)
 {
     var parts = path.Split('/');
     var attributePath = new AttributePath();
     for (var i = parts.Length - 1; i >= 0; --i)
     {
         // assume that the last one is always an attribute with empty namespace URI.  This is a valid assumption for our csdl/ssdl/msl cases
         if (i == parts.Length - 1)
         {
             attributePath.PushFront(parts[i], String.Empty, false);
         }
         else
         {
             attributePath.PushFront(parts[i], nameSpaceUri, true);
         }
     }
     return attributePath;
 }
Example #17
0
        /// <summary>
        /// Gets an attribute schema given path to it.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="resourceTraits">Locally maintained traits that can influence the returned schema.</param>
        /// <returns>A <see cref="ValueSchema"/> for the attribute.</returns>
        /// <exception cref="System.ArgumentException">
        /// Value must be provided - path
        /// or
        /// Invalid attribute path \"{path}\" - path
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack(processedPath)}\" is not a set or a list.
        /// or
        /// Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack(processedPath)}\" is not a set or a list.
        /// </exception>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">
        /// Resource does not contain an attribute \"{currentAttributeName}\".
        /// or
        /// Resource does not contain an attribute at\"{path}\".
        /// </exception>
        public ValueSchema GetAttributeByPath(string path, IResourceTraits resourceTraits)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentException("Value must be provided", nameof(path));
            }

            if (IsListIndexIndicator(path.First().ToString()) || IsListIndexIndicator(path.Last().ToString(), true))
            {
                throw new ArgumentException($"Invalid attribute path \"{path}\"", nameof(path));
            }

            if (path == "id")
            {
                // 'id' is not stored in the schema because _everything_ has it
                return(IdentitySchema);
            }

            if (resourceTraits.MissingFromSchema.Contains(path))
            {
                return(MissingFromSchemaValueSchema);
            }

            ValueSchema currentAttribute = null;
            var         currentResource  = this;
            var         pathComponents   = new Queue <string>(AttributePath.Split(path));
            var         processedPath    = new Stack <string>();

            while (true)
            {
                var currentAttributeName = pathComponents.Dequeue();

                if (IsListIndexIndicator(currentAttributeName))
                {
                    processedPath.Push(currentAttributeName);
                    continue;
                }

                var previousAttribute = currentAttribute;

                if (previousAttribute != null && previousAttribute.Type != SchemaValueType.TypeObject)
                {
                    // To get here, the previous attribute must be a set or list
                    if (!IsListIndexIndicator(processedPath.FirstOrDefault()))
                    {
                        throw new InvalidOperationException(
                                  $"Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack()}\" is a set or a list. List indicator ('*', '#' or integer) was expected next in path.");
                    }
                }

                if (currentAttributeName == "timeouts")
                {
                    currentAttribute = TimeoutsSchema;
                }
                else
                {
                    if (!currentResource.Attributes.ContainsKey(currentAttributeName))
                    {
                        throw CreateKeyNotFoundException();
                    }

                    currentAttribute = currentResource.Attributes[currentAttributeName];
                }

                processedPath.Push(currentAttributeName);

                if (pathComponents.Count == 0)
                {
                    return(currentAttribute);
                }

                switch (currentAttribute.Elem)
                {
                case ProviderResourceSchema resourceSchema:

                    currentResource = resourceSchema;
                    break;

                case ValueSchema valueSchema
                    when pathComponents.Count == 1 && currentAttribute.Type == SchemaValueType.TypeMap:

                    return(valueSchema);

                default:

                    // If Elem is null or contains a value schema, then there are no further path components
                    // below this attribute.
                    throw CreateKeyNotFoundException();
                }
            }

            KeyNotFoundException CreateKeyNotFoundException()
            {
                return(new KeyNotFoundException($"Resource does not contain an attribute at\"{path}\"."));
            }

            string GetCurrentPathFromPathStack()
            {
                return(string.Join(".", processedPath.Reverse().ToList()));
            }
        }
        public void ShouldSplitNormalPath()
        {
            const string Path = "key1.0.key2";

            AttributePath.Split(Path).Should().BeEquivalentTo(Path.Split('.'));
        }