FindSchemaNode() static private method

Find or create a schema node if createNodes is false and
An exception is only thrown if an error occurred, not if a /// node was not found.
static private FindSchemaNode ( XmpNode tree, string namespaceUri, bool createNodes ) : XmpNode
tree XmpNode the root of the xmp tree.
namespaceUri string a namespace
createNodes bool a flag indicating if the node shall be created if not found. /// Note: The namespace must be registered prior to this call. ///
return XmpNode
        /// <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
        /// <seealso cref= XMPUtils#appendProperties(XMPMeta, XMPMeta, boolean, boolean) </seealso>
        /// <param name="source"> The source XMP object. </param>
        /// <param name="destination"> The destination XMP object. </param>
        /// <param name="doAllProperties"> Do internal properties in addition to external properties. </param>
        /// <param name="replaceOldValues"> Replace the values of existing properties. </param>
        /// <param name="deleteEmptyValues"> Delete destination values if source property is empty. </param>
        /// <exception cref="XmpException"> Forwards the Exceptions from the metadata processing </exception>
        public static void AppendProperties(IXmpMeta source, IXmpMeta destination, bool doAllProperties,
                                            bool replaceOldValues, bool deleteEmptyValues)
        {
            ParameterAsserts.AssertImplementation(source);
            ParameterAsserts.AssertImplementation(destination);

            XmpMetaImpl src  = (XmpMetaImpl)source;
            XmpMetaImpl dest = (XmpMetaImpl)destination;

            for (IEnumerator it = src.Root.IterateChildren(); it.MoveNext();)
            {
                XmpNode sourceSchema = (XmpNode)it.Current;
                if (sourceSchema == null)
                {
                    continue;
                }
                // Make sure we have a destination schema node
                XmpNode destSchema    = XmpNodeUtils.FindSchemaNode(dest.Root, sourceSchema.Name, false);
                bool    createdSchema = false;
                if (destSchema == null)
                {
                    PropertyOptions propertyOptions = new PropertyOptions();
                    propertyOptions.SchemaNode = true;
                    destSchema = new XmpNode(sourceSchema.Name, sourceSchema.Value,
                                             propertyOptions);
                    dest.Root.AddChild(destSchema);
                    createdSchema = true;
                }

                // Process the source schema's children.
                for (IEnumerator ic = sourceSchema.IterateChildren(); ic.MoveNext();)
                {
                    XmpNode sourceProp = (XmpNode)ic.Current;
                    if (sourceProp == null)
                    {
                        continue;
                    }
                    if (doAllProperties || !Utils.IsInternalProperty(sourceSchema.Name, sourceProp.Name))
                    {
                        AppendSubtree(dest, sourceProp, destSchema, replaceOldValues, deleteEmptyValues);
                    }
                }

                if (!destSchema.HasChildren() && (createdSchema || deleteEmptyValues))
                {
                    // Don't create an empty schema / remove empty schema.
                    dest.Root.RemoveChild(destSchema);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Visit all schemas to do general fixes and handle special cases.
        /// </summary>
        /// <param name="xmp"> the metadata object implementation </param>
        /// <exception cref="XmpException"> Thrown if the normalisation fails. </exception>
        private static void TouchUpDataModel(XmpMetaImpl xmp)
        {
            // make sure the DC schema is existing, because it might be needed within the normalization
            // if not touched it will be removed by removeEmptySchemas
            XmpNodeUtils.FindSchemaNode(xmp.Root, XmpConst.NS_DC, true);

            // Do the special case fixes within each schema.
            IEnumerator it = xmp.Root.IterateChildren();

            while (it.MoveNext())
            {
                XmpNode currSchema = (XmpNode)it.Current;
                if (currSchema != null && XmpConst.NS_DC.Equals(currSchema.Name))
                {
                    NormalizeDcArrays(currSchema);
                }
                else if (currSchema != null && XmpConst.NS_EXIF.Equals(currSchema.Name))
                {
                    // Do a special case fix for exif:GPSTimeStamp.
                    FixGpsTimeStamp(currSchema);
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                }
                else if (currSchema != null && XmpConst.NS_DM.Equals(currSchema.Name))
                {
                    // Do a special case migration of xmpDM:copyright to
                    // dc:rights['x-default'].
                    XmpNode dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                    if (dmCopyright != null)
                    {
                        MigrateAudioCopyright(xmp, dmCopyright);
                    }
                }
                else if (currSchema != null && XmpConst.NS_XMP_RIGHTS.Equals(currSchema.Name))
                {
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                }
            }
        }
Beispiel #4
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();
            }
        }
Beispiel #5
0
        /// <summary>
        /// The initial support for WAV files mapped a legacy ID3 audio copyright
        /// into a new xmpDM:copyright property. This is special case code to migrate
        /// that into dc:rights['x-default']. The rules:
        ///
        /// <pre>
        /// 1. If there is no dc:rights array, or an empty array -
        ///    Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright.
        ///
        /// 2. If there is a dc:rights array but it has no x-default item -
        ///    Create an x-default item as a copy of the first item then apply rule #3.
        ///
        /// 3. If there is a dc:rights array with an x-default item,
        ///    Look for a double linefeed in the value.
        ///     A. If no double linefeed, compare the x-default value to the xmpDM:copyright value.
        ///         A1. If they match then leave the x-default value alone.
        ///         A2. Otherwise, append a double linefeed and
        ///             the xmpDM:copyright value to the x-default value.
        ///     B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value.
        ///         B1. If they match then leave the x-default value alone.
        ///         B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value.
        ///
        /// 4. In all cases, delete the xmpDM:copyright property.
        /// </pre>
        /// </summary>
        /// <param name="xmp"> the metadata object </param>
        /// <param name="dmCopyright"> the "dm:copyright"-property </param>
        private static void MigrateAudioCopyright(XMPMeta xmp, XmpNode dmCopyright)
        {
            try {
                XmpNode dcSchema = XmpNodeUtils.FindSchemaNode(((XmpMetaImpl)xmp).Root, XmpConst.NS_DC, true);

                string       dmValue  = dmCopyright.Value;
                const string doubleLf = "\n\n";

                XmpNode dcRightsArray = XmpNodeUtils.FindChildNode(dcSchema, "dc:rights", false);

                if (dcRightsArray == null || !dcRightsArray.HasChildren())
                {
                    // 1. No dc:rights array, create from double linefeed and xmpDM:copyright.
                    dmValue = doubleLf + dmValue;
                    xmp.SetLocalizedText(XmpConst.NS_DC, "rights", "", XmpConst.X_DEFAULT, dmValue, null);
                }
                else
                {
                    int xdIndex = XmpNodeUtils.LookupLanguageItem(dcRightsArray, XmpConst.X_DEFAULT);

                    if (xdIndex < 0)
                    {
                        // 2. No x-default item, create from the first item.
                        string firstValue = dcRightsArray.GetChild(1).Value;
                        xmp.SetLocalizedText(XmpConst.NS_DC, "rights", "", XmpConst.X_DEFAULT, firstValue, null);
                        xdIndex = XmpNodeUtils.LookupLanguageItem(dcRightsArray, XmpConst.X_DEFAULT);
                    }

                    // 3. Look for a double linefeed in the x-default value.
                    XmpNode defaultNode  = dcRightsArray.GetChild(xdIndex);
                    string  defaultValue = defaultNode.Value;
                    int     lfPos        = defaultValue.IndexOf(doubleLf);

                    if (lfPos < 0)
                    {
                        // 3A. No double LF, compare whole values.
                        if (!dmValue.Equals(defaultValue))
                        {
                            // 3A2. Append the xmpDM:copyright to the x-default
                            // item.
                            defaultNode.Value = defaultValue + doubleLf + dmValue;
                        }
                    }
                    else
                    {
                        // 3B. Has double LF, compare the tail.
                        if (!defaultValue.Substring(lfPos + 2).Equals(dmValue))
                        {
                            // 3B2. Replace the x-default tail.
                            defaultNode.Value = defaultValue.Substring(0, lfPos + 2) + dmValue;
                        }
                    }
                }

                // 4. Get rid of the xmpDM:copyright.
                dmCopyright.Parent.RemoveChild(dmCopyright);
            }
            catch (XmpException) {
                // Don't let failures (like a bad dc:rights form) stop other
                // cleanup.
            }
        }
Beispiel #6
0
        /// <summary>
        /// Visit all of the top level nodes looking for aliases. If there is
        /// no base, transplant the alias subtree. If there is a base and strict
        /// aliasing is on, make sure the alias and base subtrees match.
        /// </summary>
        /// <param name="tree"> the root of the metadata tree </param>
        /// <param name="options"> th parsing options </param>
        /// <exception cref="XmpException"> Forwards XMP errors </exception>
        private static void MoveExplicitAliases(XmpNode tree, ParseOptions options)
        {
            if (!tree.HasAliases)
            {
                return;
            }
            tree.HasAliases = false;

            bool        strictAliasing = options.StrictAliasing;
            IEnumerator schemaIt       = tree.UnmodifiableChildren.GetEnumerator();

            while (schemaIt.MoveNext())
            {
                XmpNode currSchema = (XmpNode)schemaIt.Current;
                if (currSchema == null)
                {
                    continue;
                }
                if (!currSchema.HasAliases)
                {
                    continue;
                }

                ArrayList   currPropsToRemove = new ArrayList();
                IEnumerator propertyIt        = currSchema.IterateChildren();
                while (propertyIt.MoveNext())
                {
                    XmpNode currProp = (XmpNode)propertyIt.Current;
                    if (currProp == null)
                    {
                        continue;
                    }

                    if (!currProp.Alias)
                    {
                        continue;
                    }

                    currProp.Alias = false;

                    // Find the base path, look for the base schema and root node.
                    XMPAliasInfo info = XMPMetaFactory.SchemaRegistry.FindAlias(currProp.Name);
                    if (info != null)
                    {
                        // find or create schema
                        XmpNode baseSchema = XmpNodeUtils.FindSchemaNode(tree, info.Namespace, null, true);
                        baseSchema.Implicit = false;

                        XmpNode baseNode = XmpNodeUtils.FindChildNode(baseSchema, info.Prefix + info.PropName, false);
                        if (baseNode == null)
                        {
                            if (info.AliasForm.Simple)
                            {
                                // A top-to-top alias, transplant the property.
                                // change the alias property name to the base name
                                string qname = info.Prefix + info.PropName;
                                currProp.Name = qname;
                                baseSchema.AddChild(currProp);
                            }
                            else
                            {
                                // An alias to an array item,
                                // create the array and transplant the property.
                                baseNode = new XmpNode(info.Prefix + info.PropName, info.AliasForm.ToPropertyOptions());
                                baseSchema.AddChild(baseNode);
                                TransplantArrayItemAlias(currProp, baseNode);
                            }
                            currPropsToRemove.Add(currProp);
                        }
                        else if (info.AliasForm.Simple)
                        {
                            // The base node does exist and this is a top-to-top alias.
                            // Check for conflicts if strict aliasing is on.
                            // Remove and delete the alias subtree.
                            if (strictAliasing)
                            {
                                CompareAliasedSubtrees(currProp, baseNode, true);
                            }
                            currPropsToRemove.Add(currProp);
                        }
                        else
                        {
                            // This is an alias to an array item and the array exists.
                            // Look for the aliased item.
                            // Then transplant or check & delete as appropriate.

                            XmpNode itemNode = null;
                            if (info.AliasForm.ArrayAltText)
                            {
                                int xdIndex = XmpNodeUtils.LookupLanguageItem(baseNode, XmpConst.X_DEFAULT);
                                if (xdIndex != -1)
                                {
                                    itemNode = baseNode.GetChild(xdIndex);
                                }
                            }
                            else if (baseNode.HasChildren())
                            {
                                itemNode = baseNode.GetChild(1);
                            }

                            if (itemNode == null)
                            {
                                TransplantArrayItemAlias(currProp, baseNode);
                            }
                            else
                            {
                                if (strictAliasing)
                                {
                                    CompareAliasedSubtrees(currProp, itemNode, true);
                                }
                            }
                            currPropsToRemove.Add(currProp);
                        }
                    }
                }
                foreach (object o in currPropsToRemove)
                {
                    currSchema.Children.Remove(o);
                }
                currPropsToRemove.Clear();
                currSchema.HasAliases = false;
            }
        }