/// <summary> /// Searches for a qualifier selector in a node: /// [?qualName="value"] - an element in an array, chosen by a qualifier value. /// </summary> /// <remarks> /// Searches for a qualifier selector in a node: /// [?qualName="value"] - an element in an array, chosen by a qualifier value. /// No implicit nodes are created for qualifier selectors, /// except for an alias to an x-default item. /// </remarks> /// <param name="arrayNode">an array node</param> /// <param name="qualName">the qualifier name</param> /// <param name="qualValue">the qualifier value</param> /// <param name="aliasForm"> /// in case the qual selector results from an alias, /// an x-default node is created if there has not been one. /// </param> /// <returns>Returns the index of th</returns> /// <exception cref="XmpException"></exception> private static int LookupQualSelector(XmpNode arrayNode, string qualName, string qualValue, int aliasForm) { if (XmpConstants.XmlLang.Equals(qualName)) { qualValue = Utils.NormalizeLangValue(qualValue); var index = LookupLanguageItem(arrayNode, qualValue); if (index < 0 && (aliasForm & AliasOptions.PropArrayAltText) > 0) { var langNode = new XmpNode(XmpConstants.ArrayItemName, null); var xdefault = new XmpNode(XmpConstants.XmlLang, XmpConstants.XDefault, null); langNode.AddQualifier(xdefault); arrayNode.AddChild(1, langNode); return(1); } return(index); } for (var index = 1; index < arrayNode.GetChildrenLength(); index++) { var currItem = arrayNode.GetChild(index); for (var it = currItem.IterateQualifier(); it.HasNext();) { var qualifier = (XmpNode)it.Next(); if (qualName.Equals(qualifier.Name) && qualValue.Equals(qualifier.Value)) { return(index); } } } return(-1); }
/// <summary>Moves an alias node of array form to another schema into an array</summary> /// <param name="propertyIt">the property iterator of the old schema (used to delete the property)</param> /// <param name="childNode">the node to be moved</param> /// <param name="baseArray">the base array for the array item</param> /// <exception cref="XmpException">Forwards XMP errors</exception> private static void TransplantArrayItemAlias(IIterator propertyIt, XmpNode childNode, XmpNode baseArray) { if (baseArray.Options.IsArrayAltText) { if (childNode.Options.HasLanguage) { throw new XmpException("Alias to x-default already has a language qualifier", XmpErrorCode.BadXmp); } var langQual = new XmpNode(XmpConstants.XmlLang, XmpConstants.XDefault, null); childNode.AddQualifier(langQual); } propertyIt.Remove(); childNode.Name = XmpConstants.ArrayItemName; baseArray.AddChild(childNode); }
/// <summary>Find or create a qualifier node under a given parent node.</summary> /// <remarks> /// Find or create a qualifier node under a given parent node. Returns a pointer to the /// qualifier node, and optionally an iterator for the node's position in /// the parent's vector of qualifiers. The iterator is unchanged if no qualifier node (null) /// is returned. /// <em>Note:</em> On entry, the qualName parameter must not have the leading '?' from the /// XMPPath step. /// </remarks> /// <param name="parent">the parent XMPNode</param> /// <param name="qualName">the qualifier name</param> /// <param name="createNodes">flag if nodes shall be created</param> /// <returns>Returns the qualifier node if found or created, <c>null</c> otherwise.</returns> /// <exception cref="XmpException"></exception> private static XmpNode FindQualifierNode(XmpNode parent, string qualName, bool createNodes) { Debug.Assert(!qualName.StartsWith("?")); var qualNode = parent.FindQualifierByName(qualName); if (qualNode == null && createNodes) { qualNode = new XmpNode(qualName, null) { IsImplicit = true }; parent.AddQualifier(qualNode); } return(qualNode); }
/// <summary>Appends a language item to an alt text array.</summary> /// <param name="arrayNode">the language array</param> /// <param name="itemLang">the language of the item</param> /// <param name="itemValue">the content of the item</param> /// <exception cref="XmpException">Thrown if a duplicate property is added</exception> internal static void AppendLangItem(XmpNode arrayNode, string itemLang, string itemValue) { var newItem = new XmpNode(XmpConstants.ArrayItemName, itemValue, null); var langQual = new XmpNode(XmpConstants.XmlLang, itemLang, null); newItem.AddQualifier(langQual); if (!XmpConstants.XDefault.Equals(langQual.Value)) { arrayNode.AddChild(newItem); } else { arrayNode.AddChild(1, newItem); } }
/// <summary> /// Performs a <b>deep clone</b> of the complete subtree (children and /// qualifier )into and add it to the destination node. /// </summary> /// <param name="destination">the node to add the cloned subtree</param> public void CloneSubtree(XmpNode destination) { try { for (var it = IterateChildren(); it.HasNext();) { var child = (XmpNode)it.Next(); destination.AddChild((XmpNode)child.Clone()); } for (var it1 = IterateQualifier(); it1.HasNext();) { var qualifier = (XmpNode)it1.Next(); destination.AddQualifier((XmpNode)qualifier.Clone()); } } catch (XmpException) { // cannot happen (duplicate childs/quals do not exist in this node) Debug.Assert(false); } }
/// <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(XmpMeta 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.GetRoot(), XmpConstants.NsDC, true); // Do the special case fixes within each schema. for (var it = xmp.GetRoot().IterateChildren(); it.HasNext();) { var currSchema = (XmpNode)it.Next(); switch (currSchema.Name) { case XmpConstants.NsDC: { NormalizeDcArrays(currSchema); break; } case XmpConstants.NsExif: { // Do a special case fix for exif:GPSTimeStamp. FixGpsTimeStamp(currSchema); /*var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false); * if (arrayNode != null) * { * RepairAltText(arrayNode); * }*/ var userComment = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false); if (userComment != null) { if (userComment.Options.IsSimple) { XmpNode newNode = new XmpNode(XmpConstants.ArrayItemName, userComment.Value, userComment.Options); newNode.Parent = userComment; int QualNo = userComment.GetQualifierLength(); while (QualNo > 0) { newNode.AddQualifier(userComment.GetQualifier(userComment.GetQualifierLength() - QualNo)); --QualNo; } userComment.RemoveQualifiers(); if (!newNode.Options.HasLanguage) { var po = new PropertyOptions(); po.SetOption(PropertyOptions.HasQualifiersFlag, true); XmpNode langQual = new XmpNode("xml:lang", "x-default", po); newNode.AddQualifier(langQual); newNode.Options.SetOption(PropertyOptions.HasQualifiersFlag, true); newNode.Options.SetOption(PropertyOptions.HasLanguageFlag, true); } userComment.AddChild(newNode); userComment.Options = new PropertyOptions(PropertyOptions.ArrayFlag | PropertyOptions.ArrayOrderedFlag | PropertyOptions.ArrayAltTextFlag | PropertyOptions.ArrayAlternateFlag); userComment.Value = ""; } RepairAltText(userComment); } break; } case XmpConstants.NsDm: { // Do a special case migration of xmpDM:copyright to // dc:rights['x-default']. var dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false); if (dmCopyright != null) { MigrateAudioCopyright(xmp, dmCopyright); } break; } case XmpConstants.NsXmpRights: { var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false); if (arrayNode != null) { RepairAltText(arrayNode); } break; } } } }