/// <summary> /// Tweak old XMP: Move an instance ID from rdf:about to the /// <em>xmpMM:InstanceID</em> property. /// </summary> /// <remarks> /// Tweak old XMP: Move an instance ID from rdf:about to the /// <em>xmpMM:InstanceID</em> property. An old instance ID usually looks /// like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign /// 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If /// the name looks like a UUID simply move it to <em>xmpMM:InstanceID</em>, /// don't worry about any existing <em>xmpMM:InstanceID</em>. Both will /// only be present when a newer file with the <em>xmpMM:InstanceID</em> /// property is updated by an old app that uses <em>rdf:about</em>. /// </remarks> /// <param name="tree">the root of the metadata tree</param> /// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if tweaking fails.</exception> private static void TweakOldXMP(XMPNode tree) { if (tree.GetName() != null && tree.GetName().Length >= Utils.UuidLength) { string nameStr = tree.GetName().ToLower(); if (nameStr.StartsWith("uuid:")) { nameStr = Sharpen.Runtime.Substring(nameStr, 5); } if (Utils.CheckUUIDFormat(nameStr)) { // move UUID to xmpMM:InstanceID and remove it from the root node XMPPath path = XMPPathParser.ExpandXPath(XMPConstConstants.NsXmpMm, "InstanceID"); XMPNode idNode = XMPNodeUtils.FindNode(tree, path, true, null); if (idNode != null) { idNode.SetOptions(null); // Clobber any existing xmpMM:InstanceID. idNode.SetValue("uuid:" + nameStr); idNode.RemoveChildren(); idNode.RemoveQualifiers(); tree.SetName(null); } else { throw new XMPException("Failure creating xmpMM:InstanceID", XMPErrorConstants.Internalfailure); } } } }
/// <summary> /// Tweak old XMP: Move an instance ID from rdf:about to the /// <em>xmpMM:InstanceID</em> property. /// </summary> /// <remarks> /// Tweak old XMP: Move an instance ID from rdf:about to the /// <em>xmpMM:InstanceID</em> property. An old instance ID usually looks /// like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign /// 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If /// the name looks like a UUID simply move it to <em>xmpMM:InstanceID</em>, /// don't worry about any existing <em>xmpMM:InstanceID</em>. Both will /// only be present when a newer file with the <em>xmpMM:InstanceID</em> /// property is updated by an old app that uses <em>rdf:about</em>. /// </remarks> /// <param name="tree">the root of the metadata tree</param> /// <exception cref="iText.Kernel.XMP.XMPException">Thrown if tweaking fails.</exception> private static void TweakOldXMP(XMPNode tree) { if (tree.GetName() != null && tree.GetName().Length >= Utils.UUID_LENGTH) { String nameStr = tree.GetName().ToLower(); if (nameStr.StartsWith("uuid:")) { nameStr = nameStr.Substring(5); } if (Utils.CheckUUIDFormat(nameStr)) { // move UUID to xmpMM:InstanceID and remove it from the root node XMPPath path = XMPPathParser.ExpandXPath(XMPConst.NS_XMP_MM, "InstanceID"); XMPNode idNode = XMPNodeUtils.FindNode(tree, path, true, null); if (idNode != null) { idNode.SetOptions(null); // Clobber any existing xmpMM:InstanceID. idNode.SetValue("uuid:" + nameStr); idNode.RemoveChildren(); idNode.RemoveQualifiers(); tree.SetName(null); } else { throw new XMPException("Failure creating xmpMM:InstanceID", XMPError.INTERNALFAILURE ); } } } }
public virtual XMPProperty GetLocalizedText(String schemaNS, String altTextName, String genericLang, String specificLang) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(altTextName); ParameterAsserts.AssertSpecificLang(specificLang); genericLang = genericLang != null ? iText.Kernel.XMP.Impl.Utils.NormalizeLangValue (genericLang) : null; specificLang = iText.Kernel.XMP.Impl.Utils.NormalizeLangValue(specificLang); XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, altTextName); XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null); if (arrayNode == null) { return null; } Object[] result = XMPNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang ); int match = (int)result[0]; XMPNode itemNode = (XMPNode)result[1]; if (match != XMPNodeUtils.CLT_NO_VALUES) { return new _XMPProperty_428(itemNode); } else { return null; } }
/// <summary>Constructor with optionsl initial values.</summary> /// <remarks> /// Constructor with optionsl initial values. If <code>propName</code> is provided, /// <code>schemaNS</code> has also be provided. /// </remarks> /// <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 /// <see cref="iText.Kernel.XMP.Options.IteratorOptions"/> /// </param> /// <exception cref="iText.Kernel.XMP.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 this.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.GetRoot(); } 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.GetRoot(), path, false, null); this.baseNS = schemaNS; initialPath = basePath.ToString(); } else if (baseSchema && !baseProperty) { // Only Schema provided startNode = XMPNodeUtils.FindSchemaNode(xmp.GetRoot(), 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) { this.nodeIterator = (!this.options.IsJustChildren()) ? new NodeIterator(this, startNode, initialPath, 1) : new NodeIteratorChildren(this, startNode, initialPath); } else { // create null iterator this.nodeIterator = EmptyList.GetEnumerator(); } }
// EMPTY /// <seealso cref="Com.Adobe.Xmp.XMPUtils.CatenateArrayItems(Com.Adobe.Xmp.XMPMeta, string, string, string, string, bool)"/> /// <param name="xmp">The XMP object containing the array to be catenated.</param> /// <param name="schemaNS"> /// The schema namespace URI for the array. Must not be null or /// the empty string. /// </param> /// <param name="arrayName"> /// The name of the array. May be a general path expression, must /// not be null or the empty string. Each item in the array must /// be a simple string value. /// </param> /// <param name="separator"> /// The string to be used to separate the items in the catenated /// string. Defaults to "; ", ASCII semicolon and space /// (U+003B, U+0020). /// </param> /// <param name="quotes"> /// The characters to be used as quotes around array items that /// contain a separator. Defaults to '"' /// </param> /// <param name="allowCommas">Option flag to control the catenation.</param> /// <returns>Returns the string containing the catenated array items.</returns> /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards the Exceptions from the metadata processing</exception> public static string CatenateArrayItems(XMPMeta xmp, string schemaNS, string arrayName, string separator, string quotes, bool allowCommas) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(arrayName); ParameterAsserts.AssertImplementation(xmp); if (separator == null || separator.Length == 0) { separator = "; "; } if (quotes == null || quotes.Length == 0) { quotes = "\""; } XMPMetaImpl xmpImpl = (XMPMetaImpl)xmp; XMPNode arrayNode = null; XMPNode currItem = null; // Return an empty result if the array does not exist, // hurl if it isn't the right form. XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName); arrayNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), arrayPath, false, null); if (arrayNode == null) { return(string.Empty); } else { if (!arrayNode.GetOptions().IsArray() || arrayNode.GetOptions().IsArrayAlternate()) { throw new XMPException("Named property must be non-alternate array", XMPErrorConstants.Badparam); } } // Make sure the separator is OK. CheckSeparator(separator); // Make sure the open and close quotes are a legitimate pair. char openQuote = quotes[0]; char closeQuote = CheckQuotes(quotes, openQuote); // Build the result, quoting the array items, adding separators. // Hurl if any item isn't simple. StringBuilder catinatedString = new StringBuilder(); for (Iterator it = arrayNode.IterateChildren(); it.HasNext();) { currItem = (XMPNode)it.Next(); if (currItem.GetOptions().IsCompositeProperty()) { throw new XMPException("Array items must be simple", XMPErrorConstants.Badparam); } string str = ApplyQuotes(currItem.GetValue(), openQuote, closeQuote, allowCommas); catinatedString.Append(str); if (it.HasNext()) { catinatedString.Append(separator); } } return(catinatedString.ToString()); }
/// <summary>Compose the path expression to select an alternate item by a field's value.</summary> /// <remarks> /// Compose the path expression to select an alternate item by a field's value. The path syntax /// allows two forms of "content addressing" 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, "Downloads", fieldNS, /// "City", chosenCity ); /// XMPProperty prop = xmpObj.getStructField ( schemaNS, path, fieldNS, "URI" ); /// </pre> /// </blockquote> /// </remarks> /// <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 "ns" is the /// prefix for schemaNS and "fNS" is the prefix for fieldNS. /// </returns> /// <exception cref="XMPException">Thrown if the path to create is not valid.</exception> /// <exception cref="Com.Adobe.Xmp.XMPException"/> 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", XMPErrorConstants.Badxpath); } return(arrayName + '[' + fieldPath.GetSegment(XMPPath.StepRootProp).GetName() + "=\"" + fieldValue + "\"]"); }
public virtual void AppendArrayItem(String schemaNS, String arrayName, PropertyOptions arrayOptions, String itemValue, PropertyOptions itemOptions) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(arrayName); if (arrayOptions == null) { arrayOptions = new PropertyOptions(); } if (!arrayOptions.IsOnlyArrayOptions()) { throw new XMPException("Only array form flags allowed for arrayOptions", XMPError .BADOPTIONS); } // Check if array options are set correctly. arrayOptions = XMPNodeUtils.VerifySetOptions(arrayOptions, null); // Locate or create the array. If it already exists, make sure the array // form from the options // parameter is compatible with the current state. XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName); // Just lookup, don't try to create. XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null); if (arrayNode != null) { // The array exists, make sure the form is compatible. Zero // arrayForm means take what exists. if (!arrayNode.GetOptions().IsArray()) { throw new XMPException("The named property is not an array", XMPError.BADXPATH); } } else { // if (arrayOptions != null && !arrayOptions.equalArrayTypes(arrayNode.getOptions())) // { // throw new XMPException("Mismatch of existing and specified array form", BADOPTIONS); // } // The array does not exist, try to create it. if (arrayOptions.IsArray()) { arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, true, arrayOptions); if (arrayNode == null) { throw new XMPException("Failure creating array node", XMPError.BADXPATH); } } else { // array options missing throw new XMPException("Explicit arrayOptions required to create new array", XMPError .BADOPTIONS); } } DoSetArrayItem(arrayNode, ARRAY_LAST_ITEM, itemValue, itemOptions, true); }
/// <summary>Compose the path expression to select an alternate item by a field's value.</summary> /// <remarks> /// 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: /// <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> /// </remarks> /// <param name="arrayName"> /// The name of the array. May be a general path expression, must not be /// <c>null</c> or the empty string. /// </param> /// <param name="fieldNS"> /// The namespace URI for the field used as the selector. Must not be /// <c>null</c> 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 <c>null</c> 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> 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(XMPPath.STEP_ROOT_PROP).GetName() + "=\"" + fieldValue + "\"]"); }
/// <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 "ns" is the prefix for /// schemaNS and "qNS" is the prefix for qualNS. /// </returns> /// <exception cref="XMPException">Thrown if the path to create is not valid.</exception> /// <exception cref="Com.Adobe.Xmp.XMPException"/> 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", XMPErrorConstants.Badxpath); } return("/?" + qualPath.GetSegment(XMPPath.StepRootProp).GetName()); }
/// <summary>Compose the path expression for a field in a struct.</summary> /// <remarks> /// Compose the path expression for a field in a struct. The result can be added to the /// path of /// </remarks> /// <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 "ns" is the prefix for /// schemaNS and "fNS" is the prefix for fieldNS. /// </returns> /// <exception cref="XMPException">Thrown if the path to create is not valid.</exception> /// <exception cref="Com.Adobe.Xmp.XMPException"/> 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", XMPErrorConstants.Badxpath); } return('/' + fieldPath.GetSegment(XMPPath.StepRootProp).GetName()); }
/// <summary>Compose the path expression for a field in a struct.</summary> /// <remarks> /// Compose the path expression for a field in a struct. The result can be added to the /// path of /// </remarks> /// <param name="fieldNS"> /// The namespace URI for the field. Must not be <c>null</c> or the empty /// string. /// </param> /// <param name="fieldName"> /// The name of the field. Must be a simple XML name, must not be /// <c>null</c> 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> 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(XMPPath.STEP_ROOT_PROP).GetName()); }
/// <summary>Compose the path expression for a qualifier.</summary> /// <param name="qualNS"> /// The namespace URI for the qualifier. May be <c>null</c> 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 /// <c>null</c> 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> 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(XMPPath.STEP_ROOT_PROP).GetName()); }
public virtual bool DoesPropertyExist(String schemaNS, String propName) { try { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertPropName(propName); XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName); XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null); return propNode != null; } catch (XMPException) { return false; } }
public virtual void SetProperty(String schemaNS, String propName, Object propValue , PropertyOptions options) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertPropName(propName); options = XMPNodeUtils.VerifySetOptions(options, propValue); XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName); XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, true, options); if (propNode != null) { SetNode(propNode, propValue, options, false); } else { throw new XMPException("Specified property does not exist", XMPError.BADXPATH); } }
public virtual void InsertArrayItem(String schemaNS, String arrayName, int itemIndex , String itemValue, PropertyOptions options) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(arrayName); // Just lookup, don't try to create. XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName); XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null); if (arrayNode != null) { DoSetArrayItem(arrayNode, itemIndex, itemValue, options, true); } else { throw new XMPException("Specified array does not exist", XMPError.BADXPATH); } }
public virtual void DeleteProperty(String schemaNS, String propName) { try { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertPropName(propName); XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName); XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null); if (propNode != null) { XMPNodeUtils.DeleteNode(propNode); } } catch (XMPException) { // EMPTY, exceptions are ignored within delete } }
public virtual int CountArrayItems(String schemaNS, String arrayName) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(arrayName); XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName); XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null); if (arrayNode == null) { return 0; } if (arrayNode.GetOptions().IsArray()) { return arrayNode.GetChildrenLength(); } else { throw new XMPException("The named property is not an array", XMPError.BADXPATH); } }
/// <summary>Returns a property, but the result value can be requested.</summary> /// <seealso cref="iText.Kernel.XMP.XMPMeta.GetProperty(System.String, System.String) /// "/> /// <param name="schemaNS">a schema namespace</param> /// <param name="propName">a property name or path</param> /// <param name="valueType">the type of the value, see VALUE_...</param> /// <returns> /// Returns the node value as an object according to the /// <code>valueType</code>. /// </returns> /// <exception cref="iText.Kernel.XMP.XMPException">Collects any exception that occurs.</exception> protected internal virtual Object GetPropertyObject(String schemaNS, String propName , int valueType) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertPropName(propName); XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName); XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null); if (propNode != null) { if (valueType != VALUE_STRING && propNode.GetOptions().IsCompositeProperty()) { throw new XMPException("Property must be simple when a value type is requested", XMPError.BADXPATH); } return EvaluateNodeValue(valueType, propNode); } else { return null; } }
/// <summary>Utility to find or create the array used by <code>SeparateArrayItems()</code>.</summary> /// <param name="schemaNS">a the namespace fo the array</param> /// <param name="arrayName">the name of the array</param> /// <param name="arrayOptions">the options for the array if newly created</param> /// <param name="xmp">the xmp object</param> /// <returns>Returns the array node.</returns> /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards exceptions</exception> private static XMPNode SeparateFindCreateArray(string schemaNS, string arrayName, PropertyOptions arrayOptions, XMPMetaImpl xmp) { arrayOptions = XMPNodeUtils.VerifySetOptions(arrayOptions, null); if (!arrayOptions.IsOnlyArrayOptions()) { throw new XMPException("Options can only provide array form", XMPErrorConstants.Badoptions); } // Find the array node, make sure it is OK. Move the current children // aside, to be readded later if kept. XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName); XMPNode arrayNode = XMPNodeUtils.FindNode(xmp.GetRoot(), arrayPath, false, null); if (arrayNode != null) { // The array exists, make sure the form is compatible. Zero // arrayForm means take what exists. PropertyOptions arrayForm = arrayNode.GetOptions(); if (!arrayForm.IsArray() || arrayForm.IsArrayAlternate()) { throw new XMPException("Named property must be non-alternate array", XMPErrorConstants.Badxpath); } if (arrayOptions.EqualArrayTypes(arrayForm)) { throw new XMPException("Mismatch of specified and existing array form", XMPErrorConstants.Badxpath); } } else { // *** Right error? // The array does not exist, try to create it. // don't modify the options handed into the method arrayNode = XMPNodeUtils.FindNode(xmp.GetRoot(), arrayPath, true, arrayOptions.SetArray(true)); if (arrayNode == null) { throw new XMPException("Failed to create named array", XMPErrorConstants.Badxpath); } } return(arrayNode); }
/// <seealso cref="Com.Adobe.Xmp.XMPUtils.RemoveProperties(Com.Adobe.Xmp.XMPMeta, string, string, bool, bool)"/> /// <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="Com.Adobe.Xmp.XMPException">If metadata processing fails</exception> public static void RemoveProperties(XMPMeta xmp, string schemaNS, string propName, bool doAllProperties, bool includeAliases) { ParameterAsserts.AssertImplementation(xmp); XMPMetaImpl xmpImpl = (XMPMetaImpl)xmp; if (propName != null && propName.Length > 0) { // 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 (schemaNS == null || schemaNS.Length == 0) { throw new XMPException("Property name requires schema namespace", XMPErrorConstants.Badparam); } XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName); XMPNode propNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), expPath, false, null); if (propNode != null) { if (doAllProperties || !Utils.IsInternalProperty(expPath.GetSegment(XMPPath.StepSchema).GetName(), expPath.GetSegment(XMPPath.StepRootProp).GetName())) { XMPNode parent = propNode.GetParent(); parent.RemoveChild(propNode); if (parent.GetOptions().IsSchemaNode() && !parent.HasChildren()) { // remove empty schema node parent.GetParent().RemoveChild(parent); } } } } else { if (schemaNS != null && schemaNS.Length > 0) { // 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.GetRoot(), schemaNS, false); if (schemaNode != null) { if (RemoveSchemaChildren(schemaNode, doAllProperties)) { xmpImpl.GetRoot().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. XMPAliasInfo[] aliases = XMPMetaFactory.GetSchemaRegistry().FindAliases(schemaNS); for (int i = 0; i < aliases.Length; i++) { XMPAliasInfo info = aliases[i]; XMPPath path = XMPPathParser.ExpandXPath(info.GetNamespace(), info.GetPropName()); XMPNode actualProp = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), path, false, null); if (actualProp != null) { XMPNode parent = actualProp.GetParent(); 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. for (Iterator it = xmpImpl.GetRoot().IterateChildren(); it.HasNext();) { XMPNode schema = (XMPNode)it.Next(); if (RemoveSchemaChildren(schema, doAllProperties)) { it.Remove(); } } } } }
public virtual void SetLocalizedText(String schemaNS, String altTextName, String genericLang, String specificLang, String itemValue, PropertyOptions options) { ParameterAsserts.AssertSchemaNS(schemaNS); ParameterAsserts.AssertArrayName(altTextName); ParameterAsserts.AssertSpecificLang(specificLang); genericLang = genericLang != null ? iText.Kernel.XMP.Impl.Utils.NormalizeLangValue (genericLang) : null; specificLang = iText.Kernel.XMP.Impl.Utils.NormalizeLangValue(specificLang); XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, altTextName); // Find the array node and set the options if it was just created. XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, true, new PropertyOptions (PropertyOptions.ARRAY | PropertyOptions.ARRAY_ORDERED | PropertyOptions.ARRAY_ALTERNATE | PropertyOptions.ARRAY_ALT_TEXT)); if (arrayNode == null) { throw new XMPException("Failed to find or create array node", XMPError.BADXPATH); } else { if (!arrayNode.GetOptions().IsArrayAltText()) { if (!arrayNode.HasChildren() && arrayNode.GetOptions().IsArrayAlternate()) { arrayNode.GetOptions().SetArrayAltText(true); } else { throw new XMPException("Specified property is no alt-text array", XMPError.BADXPATH ); } } } // Make sure the x-default item, if any, is first. bool haveXDefault = false; XMPNode xdItem = null; foreach (XMPNode currItem in arrayNode.GetChildren()) { if (!currItem.HasQualifier() || !XMPConst.XML_LANG.Equals(currItem.GetQualifier(1 ).GetName())) { throw new XMPException("Language qualifier must be first", XMPError.BADXPATH); } else { if (XMPConst.X_DEFAULT.Equals(currItem.GetQualifier(1).GetValue())) { xdItem = currItem; haveXDefault = true; break; } } } // Moves x-default to the beginning of the array if (xdItem != null && arrayNode.GetChildrenLength() > 1) { arrayNode.RemoveChild(xdItem); arrayNode.AddChild(1, xdItem); } // Find the appropriate item. // chooseLocalizedText will make sure the array is a language // alternative. Object[] result = XMPNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang ); int match = (int)result[0]; XMPNode itemNode = (XMPNode)result[1]; bool specificXDefault = XMPConst.X_DEFAULT.Equals(specificLang); switch (match) { case XMPNodeUtils.CLT_NO_VALUES: { // Create the array items for the specificLang and x-default, with // x-default first. XMPNodeUtils.AppendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue); haveXDefault = true; if (!specificXDefault) { XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue); } break; } case XMPNodeUtils.CLT_SPECIFIC_MATCH: { if (!specificXDefault) { // Update the specific item, update x-default if it matches the // old value. if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.GetValue().Equals (itemNode.GetValue())) { xdItem.SetValue(itemValue); } // ! Do this after the x-default check! itemNode.SetValue(itemValue); } else { // Update all items whose values match the old x-default value. System.Diagnostics.Debug.Assert(haveXDefault && xdItem == itemNode); for (IEnumerator it_1 = arrayNode.IterateChildren(); it_1.MoveNext(); ) { XMPNode currItem = (XMPNode)it_1.Current; if (currItem == xdItem || !currItem.GetValue().Equals(xdItem != null ? xdItem.GetValue () : null)) { continue; } currItem.SetValue(itemValue); } // And finally do the x-default item. if (xdItem != null) { xdItem.SetValue(itemValue); } } break; } case XMPNodeUtils.CLT_SINGLE_GENERIC: { // Update the generic item, update x-default if it matches the old // value. if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.GetValue().Equals (itemNode.GetValue())) { xdItem.SetValue(itemValue); } itemNode.SetValue(itemValue); // ! Do this after // the x-default // check! break; } case XMPNodeUtils.CLT_MULTIPLE_GENERIC: { // Create the specific language, ignore x-default. XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue); if (specificXDefault) { haveXDefault = true; } break; } case XMPNodeUtils.CLT_XDEFAULT: { // Create the specific language, update x-default if it was the only // item. if (xdItem != null && arrayNode.GetChildrenLength() == 1) { xdItem.SetValue(itemValue); } XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue); break; } case XMPNodeUtils.CLT_FIRST_ITEM: { // Create the specific language, don't add an x-default item. XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue); if (specificXDefault) { haveXDefault = true; } break; } default: { // does not happen under normal circumstances throw new XMPException("Unexpected result from ChooseLocalizedText", XMPError.INTERNALFAILURE ); } } // Add an x-default at the front if needed. if (!haveXDefault && arrayNode.GetChildrenLength() == 1) { XMPNodeUtils.AppendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue); } }
/// <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 <code>setProperty()</code>) /// </param> /// <param name="leafOptions"> /// the options for the created leaf nodes (only when /// <code>createNodes == true</code>). /// </param> /// <returns>Returns the node if found or created or <code>null</code>.</returns> /// <exception cref="Com.Adobe.Xmp.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", XMPErrorConstants.Badxpath); } // Root of implicitly created subtree to possible delete it later. // Valid only if leaf is new. XMPNode rootImplicitNode = null; XMPNode currNode = null; // resolve schema step currNode = FindSchemaNode(xmpTree, xpath.GetSegment(XMPPath.StepSchema).GetName(), createNodes); if (currNode == null) { return(null); } else { if (currNode.IsImplicit()) { currNode.SetImplicit(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 (int 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); } else { if (currNode.IsImplicit()) { // clear the implicit node flag currNode.SetImplicit(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).GetAliasForm() != 0) { currNode.GetOptions().SetOption(xpath.GetSegment(i).GetAliasForm(), true); } else { // "CheckImplicitStruct" in C++ if (i < xpath.Size() - 1 && xpath.GetSegment(i).GetKind() == XMPPath.StructFieldStep && !currNode.GetOptions().IsCompositeProperty()) { currNode.GetOptions().SetStruct(true); } } if (rootImplicitNode == null) { rootImplicitNode = currNode; } } } } } catch (XMPException e) { // 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.GetOptions().MergeWith(leafOptions); currNode.SetOptions(currNode.GetOptions()); } return(currNode); }
/// <summary>Constructor with optionsl initial values.</summary> /// <remarks> /// Constructor with optionsl initial values. If <code>propName</code> is provided, /// <code>schemaNS</code> has also be provided. /// </remarks> /// <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 /// <see cref="Com.Adobe.Xmp.Options.IteratorOptions"/> /// </param> /// <exception cref="Com.Adobe.Xmp.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 this.options = options != null ? options : new IteratorOptions(); // the start node of the iteration depending on the schema and property filter XMPNode startNode = null; string initialPath = null; bool baseSchema = schemaNS != null && schemaNS.Length > 0; bool baseProperty = propPath != null && propPath.Length > 0; if (!baseSchema && !baseProperty) { // complete tree will be iterated startNode = xmp.GetRoot(); } 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.GetRoot(), path, false, null); baseNS = schemaNS; initialPath = basePath.ToString(); } else { if (baseSchema && !baseProperty) { // Only Schema provided startNode = XMPNodeUtils.FindSchemaNode(xmp.GetRoot(), schemaNS, false); } else { // !baseSchema && baseProperty // No schema but property provided -> error throw new XMPException("Schema namespace URI is required", XMPErrorConstants.Badschema); } } } // create iterator if (startNode != null) { if (!this.options.IsJustChildren()) { nodeIterator = new XMPIteratorImpl.NodeIterator(this, startNode, initialPath, 1); } else { nodeIterator = new XMPIteratorImpl.NodeIteratorChildren(this, startNode, initialPath); } } else { // create null iterator nodeIterator = Collections.EmptyList().ListIterator(); } }