void SetRights(XmpTag xmp, string rights) { var rightsNode = xmp.FindNode("http://purl.org/dc/elements/1.1/", "rights"); if (rightsNode == null) { if (string.IsNullOrEmpty(rights)) { return; // leave it missing. } // No existing rights node, and we have some. We use (default lang) rights for copyright too, and there seems to be no way to // make the base node without setting that. So set it to something meaningless. // This will typically never happen, since our dialog requires a non-empty copyright. // I'm not entirely happy with it, but as far as I can discover the current version of taglib cannot // set the 'en' alternative of dc:rights without setting the default alternative. In fact, I'm not sure the // result of doing so would technically be valid xmp; the standard calls for every langauge alternation // to have a default. xmp.SetLangAltNode("http://purl.org/dc/elements/1.1/", "rights", "Unknown"); rightsNode = xmp.FindNode("http://purl.org/dc/elements/1.1/", "rights"); } foreach (var child in rightsNode.Children) { if (child.Namespace == "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && child.Name == "li" && HasLangQualifier(child, "en")) { if (string.IsNullOrEmpty(rights)) { rightsNode.RemoveChild(child); // enhance: possibly we should remove rightsNode, if it now has no children, and if taglib can. // However, we always require a copyright, so this will typically not happen. } else { child.Value = rights; } return; } } // Didn't find an existing rights:en node. if (string.IsNullOrEmpty(rights)) { return; // leave it missing. } var childNode = new XmpNode(XmpTag.RDF_NS, "li", rights); childNode.AddQualifier(new XmpNode(XmpTag.XML_NS, "lang", "en")); rightsNode.AddChild(childNode); }
/// <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>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> /// 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>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>The parent is an RDF pseudo-struct containing an rdf:value field.</summary> /// <remarks> /// The parent is an RDF pseudo-struct containing an rdf:value field. Fix the /// XMP data model. The rdf:value node must be the first child, the other /// children are qualifiers. The form, value, and children of the rdf:value /// node are the real ones. The rdf:value node's qualifiers must be added to /// the others. /// </remarks> /// <param name="xmpParent">the parent xmp node</param> /// <exception cref="XmpException">thrown on parsing errors</exception> private static void FixupQualifiedNode(XmpNode xmpParent) { Debug.Assert(xmpParent.Options.IsStruct && xmpParent.HasChildren); var valueNode = xmpParent.GetChild(1); Debug.Assert("rdf:value".Equals(valueNode.Name)); // Move the qualifiers on the value node to the parent. // Make sure an xml:lang qualifier stays at the front. // Check for duplicate names between the value node's qualifiers and the parent's children. // The parent's children are about to become qualifiers. Check here, between the groups. // Intra-group duplicates are caught by XMPNode#addChild(...). if (valueNode.Options.HasLanguage) { if (xmpParent.Options.HasLanguage) { throw new XmpException("Redundant xml:lang for rdf:value element", XmpErrorCode.BadXmp); } var langQual = valueNode.GetQualifier(1); valueNode.RemoveQualifier(langQual); xmpParent.AddQualifier(langQual); } // Start the remaining copy after the xml:lang qualifier. for (var i = 1; i <= valueNode.GetQualifierLength(); i++) { var qualifier = valueNode.GetQualifier(i); xmpParent.AddQualifier(qualifier); } // Change the parent's other children into qualifiers. // This loop starts at 1, child 0 is the rdf:value node. for (var i1 = 2; i1 <= xmpParent.GetChildrenLength(); i1++) { var qualifier = xmpParent.GetChild(i1); xmpParent.AddQualifier(qualifier); } // Move the options and value last, other checks need the parent's original options. // Move the value node's children to be the parent's children. Debug.Assert(xmpParent.Options.IsStruct || xmpParent.HasValueChild); xmpParent.HasValueChild = false; xmpParent.Options.IsStruct = false; xmpParent.Options.MergeWith(valueNode.Options); xmpParent.Value = valueNode.Value; xmpParent.RemoveChildren(); for (var it = valueNode.IterateChildren(); it.HasNext(); ) { var child = (XmpNode)it.Next(); xmpParent.AddChild(child); } }
/// <summary>Adds a qualifier node.</summary> /// <param name="xmpParent">the parent xmp node</param> /// <param name="name"> /// the name of the qualifier which has to be /// QName including the <b>default prefix</b> /// </param> /// <param name="value">the value of the qualifier</param> /// <returns>Returns the newly created child node.</returns> /// <exception cref="XmpException">thrown on parsing errors</exception> private static void AddQualifierNode(XmpNode xmpParent, string name, string value) { // normalize value of language qualifiers if (name == XmpConstants.XmlLang) value = Utils.NormalizeLangValue(value); xmpParent.AddQualifier(new XmpNode(name, value, null)); }