/// <summary>
        /// Constructor with optionsl initial values. If <code>propName</code> is provided,
        /// <code>schemaNs</code> has also be provided. </summary>
        /// <param name="xmp"> the iterated metadata object. </param>
        /// <param name="schemaNs"> the iteration is reduced to this schema (optional) </param>
        /// <param name="propPath"> the iteration is redurce to this property within the <code>schemaNs</code> </param>
        /// <param name="options"> advanced iteration options, see <seealso cref="IteratorOptions"/> </param>
        /// <exception cref="XmpException"> If the node defined by the paramters is not existing.  </exception>
        public XmpIteratorImpl(XmpMetaImpl xmp, string schemaNs, string propPath, IteratorOptions options)
        {
            // make sure that options is defined at least with defaults
            _options = options ?? new IteratorOptions();

            // the start node of the iteration depending on the schema and property filter
            XmpNode startNode;
            string  initialPath  = null;
            bool    baseSchema   = !String.IsNullOrEmpty(schemaNs);
            bool    baseProperty = !String.IsNullOrEmpty(propPath);

            if (!baseSchema && !baseProperty)
            {
                // complete tree will be iterated
                startNode = xmp.Root;
            }
            else if (baseSchema && baseProperty)
            {
                // Schema and property node provided
                XmpPath path = XmpPathParser.ExpandXPath(schemaNs, propPath);

                // base path is the prop path without the property leaf
                XmpPath basePath = new XmpPath();
                for (int i = 0; i < path.Size() - 1; i++)
                {
                    basePath.Add(path.GetSegment(i));
                }

                startNode   = XmpNodeUtils.FindNode(xmp.Root, path, false, null);
                _baseNs     = schemaNs;
                initialPath = basePath.ToString();
            }
            else if (baseSchema && !baseProperty)
            {
                // Only Schema provided
                startNode = XmpNodeUtils.FindSchemaNode(xmp.Root, schemaNs, false);
            }
            else // !baseSchema  &&  baseProperty
            {
                // No schema but property provided -> error
                throw new XmpException("Schema namespace URI is required", XmpError.BADSCHEMA);
            }


            // create iterator
            if (startNode != null)
            {
                _nodeIterator = (!_options.JustChildren)
                                    ? new NodeIterator(this, startNode, initialPath, 1)
                                    : new NodeIteratorChildren(this, startNode, initialPath);
            }
            else
            {
                // create null iterator
                _nodeIterator = EmptyList.GetEnumerator();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Compose the path expression to select an alternate item by a field's value. The path syntax
        /// allows two forms of &quot;content addressing&quot; that may be used to select an item in an
        /// array of alternatives. The form used in ComposeFieldSelector lets you select an item in an
        /// array of structs based on the value of one of the fields in the structs. The other form of
        /// content addressing is shown in ComposeLangSelector. For example, consider a simple struct
        /// that has two fields, the name of a city and the URI of an FTP site in that city. Use this to
        /// create an array of download alternatives. You can show the user a popup built from the values
        /// of the city fields. You can then get the corresponding URI as follows:
        /// <p>
        /// <blockquote>
        ///
        /// <pre>
        ///      String path = composeFieldSelector ( schemaNs, &quot;Downloads&quot;, fieldNs,
        ///          &quot;City&quot;, chosenCity );
        ///      XMPProperty prop = xmpObj.getStructField ( schemaNs, path, fieldNs, &quot;URI&quot; );
        /// </pre>
        ///
        /// </blockquote>
        /// </summary>
        /// <param name="arrayName"> The name of the array. May be a general path expression, must not be
        ///        <code>null</code> or the empty string. </param>
        /// <param name="fieldNs"> The namespace URI for the field used as the selector. Must not be
        ///        <code>null</code> or the empty string. </param>
        /// <param name="fieldName"> The name of the field used as the selector. Must be a simple XML name, must
        ///        not be <code>null</code> or the empty string. It must be the name of a field that is
        ///        itself simple. </param>
        /// <param name="fieldValue"> The desired value of the field. </param>
        /// <returns> Returns the composed path. This will be of the form
        ///         <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where &quot;ns&quot; is the
        ///         prefix for schemaNs and &quot;fNS&quot; is the prefix for fieldNs. </returns>
        /// <exception cref="XmpException"> Thrown if the path to create is not valid. </exception>
        public static string ComposeFieldSelector(string arrayName, string fieldNs, string fieldName, string fieldValue)
        {
            XmpPath fieldPath = XmpPathParser.ExpandXPath(fieldNs, fieldName);

            if (fieldPath.Size() != 2)
            {
                throw new XmpException("The fieldName name must be simple", XmpError.BADXPATH);
            }

            return(arrayName + '[' + fieldPath.GetSegment((int)XmpPath.STEP_ROOT_PROP).Name + "=\"" + fieldValue +
                   "\"]");
        }
Beispiel #3
0
        /// <summary>
        /// Compose the path expression for a qualifier.
        /// </summary>
        /// <param name="qualNs"> The namespace URI for the qualifier. May be <code>null</code> or the empty
        ///        string if the qualifier is in the XML empty namespace. </param>
        /// <param name="qualName"> The name of the qualifier. Must be a simple XML name, must not be
        ///        <code>null</code> or the empty string. </param>
        /// <returns> Returns the composed path. This will be of the form
        ///         <tt>ns:propName/?qNS:qualName</tt>, where &quot;ns&quot; is the prefix for
        ///         schemaNs and &quot;qNS&quot; is the prefix for qualNs. </returns>
        /// <exception cref="XmpException"> Thrown if the path to create is not valid. </exception>
        public static string ComposeQualifierPath(string qualNs, string qualName)
        {
            AssertQualNs(qualNs);
            AssertQualName(qualName);

            XmpPath qualPath = XmpPathParser.ExpandXPath(qualNs, qualName);

            if (qualPath.Size() != 2)
            {
                throw new XmpException("The qualifier name must be simple", XmpError.BADXPATH);
            }

            return("/?" + qualPath.GetSegment((int)XmpPath.STEP_ROOT_PROP).Name);
        }
Beispiel #4
0
        /// <summary>
        /// Compose the path expression for a field in a struct. The result can be added to the
        /// path of
        ///
        /// </summary>
        /// <param name="fieldNs"> The namespace URI for the field. Must not be <code>null</code> or the empty
        ///        string. </param>
        /// <param name="fieldName"> The name of the field. Must be a simple XML name, must not be
        ///        <code>null</code> or the empty string. </param>
        /// <returns> Returns the composed path. This will be of the form
        ///         <tt>ns:structName/fNS:fieldName</tt>, where &quot;ns&quot; is the prefix for
        ///         schemaNs and &quot;fNS&quot; is the prefix for fieldNs. </returns>
        /// <exception cref="XmpException"> Thrown if the path to create is not valid. </exception>
        public static string ComposeStructFieldPath(string fieldNs, string fieldName)
        {
            AssertFieldNs(fieldNs);
            AssertFieldName(fieldName);

            XmpPath fieldPath = XmpPathParser.ExpandXPath(fieldNs, fieldName);

            if (fieldPath.Size() != 2)
            {
                throw new XmpException("The field name must be simple", XmpError.BADXPATH);
            }

            return('/' + fieldPath.GetSegment((int)XmpPath.STEP_ROOT_PROP).Name);
        }
        /// <summary>Follow an expanded path expression to find or create a node.</summary>
        /// <param name="xmpTree">the node to begin the search.</param>
        /// <param name="xpath">the complete xpath</param>
        /// <param name="createNodes">
        /// flag if nodes shall be created
        /// (when called by <c>setProperty()</c>)
        /// </param>
        /// <param name="leafOptions">
        /// the options for the created leaf nodes (only when
        /// <c>createNodes == true</c>).
        /// </param>
        /// <returns>Returns the node if found or created or <c>null</c>.</returns>
        /// <exception cref="XmpException">
        /// An exception is only thrown if an error occurred,
        /// not if a node was not found.
        /// </exception>
        internal static XmpNode FindNode(XmpNode xmpTree, XmpPath xpath, bool createNodes, PropertyOptions leafOptions)
        {
            // check if xpath is set.
            if (xpath == null || xpath.Size() == 0)
            {
                throw new XmpException("Empty XMPPath", XmpErrorCode.BadXPath);
            }

            // Root of implicitly created subtree to possible delete it later.
            // Valid only if leaf is new.
            XmpNode rootImplicitNode = null;

            // resolve schema step
            var currNode = FindSchemaNode(xmpTree, xpath.GetSegment(XmpPath.StepSchema).Name, createNodes);

            if (currNode == null)
            {
                return(null);
            }

            if (currNode.IsImplicit)
            {
                currNode.IsImplicit = false;
                // Clear the implicit node bit.
                rootImplicitNode = currNode;
            }

            // Save the top most implicit node.
            // Now follow the remaining steps of the original XMPPath.
            try
            {
                for (var i = 1; i < xpath.Size(); i++)
                {
                    currNode = FollowXPathStep(currNode, xpath.GetSegment(i), createNodes);
                    if (currNode == null)
                    {
                        if (createNodes)
                        {
                            // delete implicitly created nodes
                            DeleteNode(rootImplicitNode);
                        }
                        return(null);
                    }

                    if (currNode.IsImplicit)
                    {
                        // clear the implicit node flag
                        currNode.IsImplicit = false;
                        // if node is an ALIAS (can be only in root step, auto-create array
                        // when the path has been resolved from a not simple alias type
                        if (i == 1 && xpath.GetSegment(i).IsAlias&& xpath.GetSegment(i).AliasForm != 0)
                        {
                            currNode.Options.SetOption(xpath.GetSegment(i).AliasForm, true);
                        }
                        else
                        {
                            // "CheckImplicitStruct" in C++
                            if (i < xpath.Size() - 1 && xpath.GetSegment(i).Kind == XmpPathStepType.StructFieldStep && !currNode.Options.IsCompositeProperty)
                            {
                                currNode.Options.IsStruct = true;
                            }
                        }

                        if (rootImplicitNode == null)
                        {
                            rootImplicitNode = currNode;
                        }
                    }
                }
            }
            catch (XmpException)
            {
                // Save the top most implicit node.
                // if new notes have been created prior to the error, delete them
                if (rootImplicitNode != null)
                {
                    DeleteNode(rootImplicitNode);
                }

                throw;
            }

            if (rootImplicitNode != null)
            {
                // set options only if a node has been successful created
                currNode.Options.MergeWith(leafOptions);
                currNode.Options = currNode.Options;
            }

            return(currNode);
        }
Beispiel #6
0
        /// <seealso cref= XMPUtils#removeProperties(XMPMeta, String, String, boolean, boolean)
        /// </seealso>
        /// <param name="xmp">
        ///            The XMP object containing the properties to be removed.
        /// </param>
        /// <param name="schemaNs">
        ///            Optional schema namespace URI for the properties to be
        ///            removed.
        /// </param>
        /// <param name="propName">
        ///            Optional path expression for the property to be removed.
        /// </param>
        /// <param name="doAllProperties">
        ///            Option flag to control the deletion: do internal properties in
        ///            addition to external properties. </param>
        /// <param name="includeAliases">
        ///            Option flag to control the deletion: Include aliases in the
        ///            "named schema" case above. </param>
        /// <exception cref="XmpException"> If metadata processing fails </exception>
        public static void RemoveProperties(IXmpMeta xmp, string schemaNs, string propName, bool doAllProperties,
                                            bool includeAliases)
        {
            ParameterAsserts.AssertImplementation(xmp);
            XmpMetaImpl xmpImpl = (XmpMetaImpl)xmp;

            if (!string.IsNullOrEmpty(propName))
            {
                // Remove just the one indicated property. This might be an alias,
                // the named schema might not actually exist. So don't lookup the
                // schema node.

                if (string.IsNullOrEmpty(schemaNs))
                {
                    throw new XmpException("Property name requires schema namespace", XmpError.BADPARAM);
                }

                XmpPath expPath = XmpPathParser.ExpandXPath(schemaNs, propName);

                XmpNode propNode = XmpNodeUtils.FindNode(xmpImpl.Root, expPath, false, null);
                if (propNode != null)
                {
                    if (doAllProperties ||
                        !Utils.IsInternalProperty(expPath.GetSegment((int)XmpPath.STEP_SCHEMA).Name,
                                                  expPath.GetSegment((int)XmpPath.STEP_ROOT_PROP).Name))
                    {
                        XmpNode parent = propNode.Parent;
                        parent.RemoveChild(propNode);
                        if (parent.Options.SchemaNode && !parent.HasChildren())
                        {
                            // remove empty schema node
                            parent.Parent.RemoveChild(parent);
                        }
                    }
                }
            }
            else if (!string.IsNullOrEmpty(schemaNs))
            {
                // Remove all properties from the named schema. Optionally include
                // aliases, in which case
                // there might not be an actual schema node.

                // XMP_NodePtrPos schemaPos;
                XmpNode schemaNode = XmpNodeUtils.FindSchemaNode(xmpImpl.Root, schemaNs, false);
                if (schemaNode != null)
                {
                    if (RemoveSchemaChildren(schemaNode, doAllProperties))
                    {
                        xmpImpl.Root.RemoveChild(schemaNode);
                    }
                }

                if (includeAliases)
                {
                    // We're removing the aliases also. Look them up by their
                    // namespace prefix.
                    // But that takes more code and the extra speed isn't worth it.
                    // Lookup the XMP node
                    // from the alias, to make sure the actual exists.

                    IXmpAliasInfo[] aliases = XmpMetaFactory.SchemaRegistry.FindAliases(schemaNs);
                    for (int i = 0; i < aliases.Length; i++)
                    {
                        IXmpAliasInfo info       = aliases[i];
                        XmpPath       path       = XmpPathParser.ExpandXPath(info.Namespace, info.PropName);
                        XmpNode       actualProp = XmpNodeUtils.FindNode(xmpImpl.Root, path, false, null);
                        if (actualProp != null)
                        {
                            XmpNode parent = actualProp.Parent;
                            parent.RemoveChild(actualProp);
                        }
                    }
                }
            }
            else
            {
                // Remove all appropriate properties from all schema. In this case
                // we don't have to be
                // concerned with aliases, they are handled implicitly from the
                // actual properties.
                ArrayList schemasToRemove = new ArrayList();
                for (IEnumerator it = xmpImpl.Root.IterateChildren(); it.MoveNext();)
                {
                    XmpNode schema = (XmpNode)it.Current;
                    if (schema == null)
                    {
                        continue;
                    }
                    if (RemoveSchemaChildren(schema, doAllProperties))
                    {
                        schemasToRemove.Add(schema);
                    }
                }
                foreach (XmpNode xmpNode in schemasToRemove)
                {
                    xmpImpl.Root.Children.Remove(xmpNode);
                }
                schemasToRemove.Clear();
            }
        }