/// <summary>Find or create a child node under a given parent node.</summary> /// <remarks> /// Find or create a child node under a given parent node. If the parent node is no /// Returns the found or created child node. /// </remarks> /// <param name="parent">the parent node</param> /// <param name="childName">the node name to find</param> /// <param name="createNodes">flag, if new nodes shall be created.</param> /// <returns>Returns the found or created node or <code>null</code>.</returns> /// <exception cref="iText.Kernel.XMP.XMPException">Thrown if</exception> internal static XMPNode FindChildNode(XMPNode parent, String childName, bool createNodes ) { if (!parent.GetOptions().IsSchemaNode() && !parent.GetOptions().IsStruct()) { if (!parent.IsImplicit()) { throw new XMPException("Named children only allowed for schemas and structs", XMPError .BADXPATH); } else { if (parent.GetOptions().IsArray()) { throw new XMPException("Named children not allowed for arrays", XMPError.BADXPATH ); } else { if (createNodes) { parent.GetOptions().SetStruct(true); } } } } XMPNode childNode = parent.FindChildByName(childName); if (childNode == null && createNodes) { PropertyOptions options = new PropertyOptions(); childNode = new XMPNode(childName, options); childNode.SetImplicit(true); parent.AddChild(childNode); } System.Diagnostics.Debug.Assert(childNode != null || !createNodes); return(childNode); }
/// <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="iText.Kernel.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", XMPError.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.STEP_SCHEMA).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.STRUCT_FIELD_STEP && !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); }