/// <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(); } }
/// <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 + "\"]"); }
/// <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 <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()); }
/// <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 <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>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(); } }