Beispiel #1
0
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <ul>
        ///     <li>qualName - A top level property or struct field.
        /// <li>[index] - An element of an array.
        /// <li>[last()] - The last element of an array.
        /// <li>[qualName="value"] - An element in an array of structs, chosen by a field value.
        /// <li>[?qualName="value"] - An element in an array, chosen by a qualifier value.
        /// <li>?qualName - A general qualifier.
        /// </ul>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </summary>
        /// <param name="parentNode"> the node to start to start from </param>
        /// <param name="nextStep"> the xpath segment </param>
        /// <param name="createNodes"> </param>
        /// <returns> returns the found or created XmpPath node </returns>
        /// <exception cref="XmpException">  </exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes)
        {
            XmpNode nextNode = null;
            uint    stepKind = nextStep.Kind;

            if (stepKind == XmpPath.STRUCT_FIELD_STEP)
            {
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
            }
            else if (stepKind == XmpPath.QUALIFIER_STEP)
            {
                nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
            }
            else
            {
                // This is an array indexing step. First get the index, then get the node.
                int index;

                if (!parentNode.Options.Array)
                {
                    throw new XmpException("Indexing applied to non-array", XmpError.BADXPATH);
                }

                if (stepKind == XmpPath.ARRAY_INDEX_STEP)
                {
                    index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                }
                else if (stepKind == XmpPath.ARRAY_LAST_STEP)
                {
                    index = parentNode.ChildrenLength;
                }
                else if (stepKind == XmpPath.FIELD_SELECTOR_STEP)
                {
                    string[] result     = Utils.SplitNameAndValue(nextStep.Name);
                    string   fieldName  = result[0];
                    string   fieldValue = result[1];
                    index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                }
                else if (stepKind == XmpPath.QUAL_SELECTOR_STEP)
                {
                    string[] result    = Utils.SplitNameAndValue(nextStep.Name);
                    string   qualName  = result[0];
                    string   qualValue = result[1];
                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                }
                else
                {
                    throw new XmpException("Unknown array indexing step in FollowXPathStep",
                                           XmpError.INTERNALFAILURE);
                }

                if (1 <= index && index <= parentNode.ChildrenLength)
                {
                    nextNode = parentNode.GetChild(index);
                }
            }

            return(nextNode);
        }
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// </summary>
        /// <remarks>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <list type="bullet">
        /// <item>qualName - A top level property or struct field.</item>
        /// <item>[index] - An element of an array.</item>
        /// <item>[last()] - The last element of an array.</item>
        /// <item>[qualName="value"] - An element in an array of structs, chosen by a field value.</item>
        /// <item>[?qualName="value"] - An element in an array, chosen by a qualifier value.</item>
        /// <item>?qualName - A general qualifier.</item>
        /// </list>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </remarks>
        /// <param name="parentNode">the node to start to start from</param>
        /// <param name="nextStep">the xpath segment</param>
        /// <param name="createNodes"></param>
        /// <returns>returns the found or created XMPPath node</returns>
        /// <exception cref="XmpException"></exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes)
        {
            XmpNode nextNode = null;
            var     stepKind = nextStep.Kind;

            switch (stepKind)
            {
            case XmpPathStepType.StructFieldStep:
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
                break;

            case XmpPathStepType.QualifierStep:
                nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
                break;

            default:
                // This is an array indexing step. First get the index, then get the node.
                if (!parentNode.Options.IsArray)
                {
                    throw new XmpException("Indexing applied to non-array", XmpErrorCode.BadXPath);
                }

                int index;
                switch (stepKind)
                {
                case XmpPathStepType.ArrayIndexStep:
                    index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                    break;

                case XmpPathStepType.ArrayLastStep:
                    index = parentNode.GetChildrenLength();
                    break;

                case XmpPathStepType.FieldSelectorStep:
                    Utils.SplitNameAndValue(nextStep.Name, out string fieldName, out string fieldValue);
                    index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                    break;

                case XmpPathStepType.QualSelectorStep:
                    Utils.SplitNameAndValue(nextStep.Name, out string qualName, out string qualValue);
                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                    break;

                default:
                    throw new XmpException("Unknown array indexing step in FollowXPathStep", XmpErrorCode.InternalFailure);
                }

                if (1 <= index && index <= parentNode.GetChildrenLength())
                {
                    nextNode = parentNode.GetChild(index);
                }
                break;
            }

            return(nextNode);
        }
        /// <summary>
        /// Parses the root node of an XMP Path, checks if namespace and prefix fit together
        /// and resolve the property to the base property if it is an alias.
        /// </summary>
        /// <param name="schemaNs">the root namespace</param>
        /// <param name="pos">the parsing position helper</param>
        /// <param name="expandedXPath">the path to contribute to</param>
        /// <exception cref="XmpException">If the path is not valid.</exception>
        private static void ParseRootNode(string schemaNs, PathPosition pos, XmpPath expandedXPath)
        {
            while (pos.StepEnd < pos.Path.Length && "/[*".IndexOf(pos.Path[pos.StepEnd]) < 0)
            {
                pos.StepEnd++;
            }

            if (pos.StepEnd == pos.StepBegin)
            {
                throw new XmpException("Empty initial XMPPath step", XmpErrorCode.BadXPath);
            }

            var rootProp  = VerifyXPathRoot(schemaNs, pos.Path.Substring(pos.StepBegin, pos.StepEnd - pos.StepBegin));
            var aliasInfo = XmpMetaFactory.SchemaRegistry.FindAlias(rootProp);

            if (aliasInfo == null)
            {
                // add schema xpath step
                expandedXPath.Add(new XmpPathSegment(schemaNs, XmpPathStepType.SchemaNode));
                var rootStep = new XmpPathSegment(rootProp, XmpPathStepType.StructFieldStep);
                expandedXPath.Add(rootStep);
                return;
            }

            // add schema xpath step and base step of alias
            expandedXPath.Add(new XmpPathSegment(aliasInfo.Namespace, XmpPathStepType.SchemaNode));
            expandedXPath.Add(new XmpPathSegment(VerifyXPathRoot(aliasInfo.Namespace, aliasInfo.PropName), XmpPathStepType.StructFieldStep)
            {
                IsAlias   = true,
                AliasForm = aliasInfo.AliasForm.GetOptions()
            });

            if (aliasInfo.AliasForm.IsArrayAltText)
            {
                expandedXPath.Add(new XmpPathSegment("[?xml:lang='x-default']", XmpPathStepType.QualSelectorStep)
                {
                    IsAlias   = true,
                    AliasForm = aliasInfo.AliasForm.GetOptions()
                });
            }
            else if (aliasInfo.AliasForm.IsArray)
            {
                expandedXPath.Add(new XmpPathSegment("[1]", XmpPathStepType.ArrayIndexStep)
                {
                    IsAlias   = true,
                    AliasForm = aliasInfo.AliasForm.GetOptions()
                });
            }
        }
        /// <summary>Parses an array index segment.</summary>
        /// <param name="pos">the xmp path</param>
        /// <returns>Returns the segment or an error</returns>
        /// <exception cref="XmpException">thrown on xmp path errors</exception>
        private static XmpPathSegment ParseIndexSegment(PathPosition pos)
        {
            XmpPathSegment segment;

            pos.StepEnd++;

            // Look at the character after the leading '['.
            if ('0' <= pos.Path[pos.StepEnd] && pos.Path[pos.StepEnd] <= '9')
            {
                // A numeric (decimal integer) array index.
                while (pos.StepEnd < pos.Path.Length && '0' <= pos.Path[pos.StepEnd] && pos.Path[pos.StepEnd] <= '9')
                {
                    pos.StepEnd++;
                }

                segment = new XmpPathSegment(null, XmpPath.ArrayIndexStep);
            }
            else
            {
                // Could be "[last()]" or one of the selector forms. Find the ']' or '='.
                while (pos.StepEnd < pos.Path.Length && pos.Path[pos.StepEnd] != ']' && pos.Path[pos.StepEnd] != '=')
                {
                    pos.StepEnd++;
                }

                if (pos.StepEnd >= pos.Path.Length)
                {
                    throw new XmpException("Missing ']' or '=' for array index", XmpErrorCode.BadXPath);
                }

                if (pos.Path[pos.StepEnd] == ']')
                {
                    if (!"[last()".Equals(pos.Path.Substring(pos.StepBegin, pos.StepEnd - pos.StepBegin)))
                    {
                        throw new XmpException("Invalid non-numeric array index", XmpErrorCode.BadXPath);
                    }

                    segment = new XmpPathSegment(null, XmpPath.ArrayLastStep);
                }
                else
                {
                    pos.NameStart = pos.StepBegin + 1;
                    pos.NameEnd   = pos.StepEnd;
                    pos.StepEnd++;

                    // Absorb the '=', remember the quote.
                    var quote = pos.Path[pos.StepEnd];
                    if (quote != '\'' && quote != '"')
                    {
                        throw new XmpException("Invalid quote in array selector", XmpErrorCode.BadXPath);
                    }

                    pos.StepEnd++;

                    // Absorb the leading quote.
                    while (pos.StepEnd < pos.Path.Length)
                    {
                        if (pos.Path[pos.StepEnd] == quote)
                        {
                            // check for escaped quote
                            if (pos.StepEnd + 1 >= pos.Path.Length || pos.Path[pos.StepEnd + 1] != quote)
                            {
                                break;
                            }

                            pos.StepEnd++;
                        }
                        pos.StepEnd++;
                    }

                    if (pos.StepEnd >= pos.Path.Length)
                    {
                        throw new XmpException("No terminating quote for array selector", XmpErrorCode.BadXPath);
                    }

                    pos.StepEnd++;

                    // Absorb the trailing quote.
                    // ! Touch up later, also changing '@' to '?'.
                    segment = new XmpPathSegment(null, XmpPath.FieldSelectorStep);
                }
            }

            if (pos.StepEnd >= pos.Path.Length || pos.Path[pos.StepEnd] != ']')
            {
                throw new XmpException("Missing ']' for array index", XmpErrorCode.BadXPath);
            }

            pos.StepEnd++;
            segment.Name = pos.Path.Substring(pos.StepBegin, pos.StepEnd - pos.StepBegin);

            return(segment);
        }
        /// <summary>
        /// Parses the root node of an XMP Path, checks if namespace and prefix fit together
        /// and resolve the property to the base property if it is an alias.
        /// </summary>
        /// <param name="schemaNs">the root namespace</param>
        /// <param name="pos">the parsing position helper</param>
        /// <param name="expandedXPath">the path to contribute to</param>
        /// <exception cref="XmpException">If the path is not valid.</exception>
        private static void ParseRootNode(string schemaNs, PathPosition pos, XmpPath expandedXPath)
        {
            while (pos.StepEnd < pos.Path.Length && "/[*".IndexOf(pos.Path[pos.StepEnd]) < 0)
                pos.StepEnd++;

            if (pos.StepEnd == pos.StepBegin)
                throw new XmpException("Empty initial XMPPath step", XmpErrorCode.BadXPath);

            var rootProp = VerifyXPathRoot(schemaNs, pos.Path.Substring (pos.StepBegin, pos.StepEnd - pos.StepBegin));
            var aliasInfo = XmpMetaFactory.SchemaRegistry.FindAlias(rootProp);

            if (aliasInfo == null)
            {
                // add schema xpath step
                expandedXPath.Add(new XmpPathSegment(schemaNs, XmpPath.SchemaNode));
                var rootStep = new XmpPathSegment(rootProp, XmpPath.StructFieldStep);
                expandedXPath.Add(rootStep);
            }
            else
            {
                // add schema xpath step and base step of alias
                expandedXPath.Add(new XmpPathSegment(aliasInfo.Namespace, XmpPath.SchemaNode));
                var rootStep = new XmpPathSegment(VerifyXPathRoot(aliasInfo.Namespace, aliasInfo.PropName), XmpPath.StructFieldStep);
                rootStep.IsAlias = true;
                rootStep.AliasForm = aliasInfo.AliasForm.GetOptions();
                expandedXPath.Add(rootStep);

                if (aliasInfo.AliasForm.IsArrayAltText)
                {
                    var qualSelectorStep = new XmpPathSegment("[?xml:lang='x-default']", XmpPath.QualSelectorStep);
                    qualSelectorStep.IsAlias = true;
                    qualSelectorStep.AliasForm = aliasInfo.AliasForm.GetOptions();
                    expandedXPath.Add(qualSelectorStep);
                }
                else if (aliasInfo.AliasForm.IsArray)
                {
                    var indexStep = new XmpPathSegment("[1]", XmpPath.ArrayIndexStep);
                    indexStep.IsAlias = true;
                    indexStep.AliasForm = aliasInfo.AliasForm.GetOptions();
                    expandedXPath.Add(indexStep);
                }
            }
        }
        /// <summary>Parses an array index segment.</summary>
        /// <param name="pos">the xmp path</param>
        /// <returns>Returns the segment or an error</returns>
        /// <exception cref="XmpException">thrown on xmp path errors</exception>
        private static XmpPathSegment ParseIndexSegment(PathPosition pos)
        {
            XmpPathSegment segment;
            pos.StepEnd++;

            // Look at the character after the leading '['.
            if ('0' <= pos.Path[pos.StepEnd] && pos.Path[pos.StepEnd] <= '9')
            {
                // A numeric (decimal integer) array index.
                while (pos.StepEnd < pos.Path.Length && '0' <= pos.Path[pos.StepEnd] && pos.Path[pos.StepEnd] <= '9')
                    pos.StepEnd++;

                segment = new XmpPathSegment(null, XmpPath.ArrayIndexStep);
            }
            else
            {
                // Could be "[last()]" or one of the selector forms. Find the ']' or '='.
                while (pos.StepEnd < pos.Path.Length && pos.Path[pos.StepEnd] != ']' && pos.Path[pos.StepEnd] != '=')
                    pos.StepEnd++;

                if (pos.StepEnd >= pos.Path.Length)
                    throw new XmpException("Missing ']' or '=' for array index", XmpErrorCode.BadXPath);

                if (pos.Path[pos.StepEnd] == ']')
                {
                    if (!"[last()".Equals(pos.Path.Substring(pos.StepBegin, pos.StepEnd - pos.StepBegin)))
                        throw new XmpException("Invalid non-numeric array index", XmpErrorCode.BadXPath);

                    segment = new XmpPathSegment(null, XmpPath.ArrayLastStep);
                }
                else
                {
                    pos.NameStart = pos.StepBegin + 1;
                    pos.NameEnd = pos.StepEnd;
                    pos.StepEnd++;

                    // Absorb the '=', remember the quote.
                    var quote = pos.Path[pos.StepEnd];
                    if (quote != '\'' && quote != '"')
                        throw new XmpException("Invalid quote in array selector", XmpErrorCode.BadXPath);

                    pos.StepEnd++;

                    // Absorb the leading quote.
                    while (pos.StepEnd < pos.Path.Length)
                    {
                        if (pos.Path[pos.StepEnd] == quote)
                        {
                            // check for escaped quote
                            if (pos.StepEnd + 1 >= pos.Path.Length || pos.Path[pos.StepEnd + 1] != quote)
                                break;

                            pos.StepEnd++;
                        }
                        pos.StepEnd++;
                    }

                    if (pos.StepEnd >= pos.Path.Length)
                        throw new XmpException("No terminating quote for array selector", XmpErrorCode.BadXPath);

                    pos.StepEnd++;

                    // Absorb the trailing quote.
                    // ! Touch up later, also changing '@' to '?'.
                    segment = new XmpPathSegment(null, XmpPath.FieldSelectorStep);
                }
            }

            if (pos.StepEnd >= pos.Path.Length || pos.Path[pos.StepEnd] != ']')
                throw new XmpException("Missing ']' for array index", XmpErrorCode.BadXPath);

            pos.StepEnd++;
            segment.Name = pos.Path.Substring (pos.StepBegin, pos.StepEnd - pos.StepBegin);

            return segment;
        }
Beispiel #7
0
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// </summary>
        /// <remarks>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <list type="bullet">
        /// <item>qualName - A top level property or struct field.</item>
        /// <item>[index] - An element of an array.</item>
        /// <item>[last()] - The last element of an array.</item>
        /// <item>[qualName="value"] - An element in an array of structs, chosen by a field value.</item>
        /// <item>[?qualName="value"] - An element in an array, chosen by a qualifier value.</item>
        /// <item>?qualName - A general qualifier.</item>
        /// </list>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </remarks>
        /// <param name="parentNode">the node to start to start from</param>
        /// <param name="nextStep">the xpath segment</param>
        /// <param name="createNodes"></param>
        /// <returns>returns the found or created XMPPath node</returns>
        /// <exception cref="XmpException"></exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes)
        {
            XmpNode nextNode = null;
            var     stepKind = nextStep.Kind;

            if (stepKind == XmpPath.StructFieldStep)
            {
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
            }
            else
            {
                if (stepKind == XmpPath.QualifierStep)
                {
                    nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
                }
                else
                {
                    // This is an array indexing step. First get the index, then get the node.
                    if (!parentNode.Options.IsArray)
                    {
                        throw new XmpException("Indexing applied to non-array", XmpErrorCode.BadXPath);
                    }
                    var index = 0;
                    if (stepKind == XmpPath.ArrayIndexStep)
                    {
                        index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                    }
                    else
                    {
                        if (stepKind == XmpPath.ArrayLastStep)
                        {
                            index = parentNode.GetChildrenLength();
                        }
                        else
                        {
                            if (stepKind == XmpPath.FieldSelectorStep)
                            {
                                var result     = Utils.SplitNameAndValue(nextStep.Name);
                                var fieldName  = result[0];
                                var fieldValue = result[1];
                                index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                            }
                            else
                            {
                                if (stepKind == XmpPath.QualSelectorStep)
                                {
                                    var result    = Utils.SplitNameAndValue(nextStep.Name);
                                    var qualName  = result[0];
                                    var qualValue = result[1];
                                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                                }
                                else
                                {
                                    throw new XmpException("Unknown array indexing step in FollowXPathStep", XmpErrorCode.InternalFailure);
                                }
                            }
                        }
                    }
                    if (1 <= index && index <= parentNode.GetChildrenLength())
                    {
                        nextNode = parentNode.GetChild(index);
                    }
                }
            }
            return(nextNode);
        }