/// <summary>Deletes the the given node and its children from its parent.</summary> /// <remarks> /// Deletes the the given node and its children from its parent. /// Takes care about adjusting the flags. /// </remarks> /// <param name="node">the top-most node to delete.</param> internal static void DeleteNode(XMPNode node) { XMPNode parent = node.GetParent(); if (node.GetOptions().IsQualifier()) { // root is qualifier parent.RemoveQualifier(node); } else { // root is NO qualifier parent.RemoveChild(node); } // delete empty Schema nodes if (!parent.HasChildren() && parent.GetOptions().IsSchemaNode()) { parent.GetParent().RemoveChild(parent); } }
/// <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>See if an array is an alt-text array.</summary> /// <remarks> /// See if an array is an alt-text array. If so, make sure the x-default item /// is first. /// </remarks> /// <param name="arrayNode">the array node to check if its an alt-text array</param> internal static void DetectAltText(XMPNode arrayNode) { if (arrayNode.GetOptions().IsArrayAlternate() && arrayNode.HasChildren()) { bool isAltText = false; for (IEnumerator it = arrayNode.IterateChildren(); it.MoveNext();) { XMPNode child = (XMPNode)it.Current; if (child.GetOptions().GetHasLanguage()) { isAltText = true; break; } } if (isAltText) { arrayNode.GetOptions().SetArrayAltText(true); NormalizeLangArray(arrayNode); } } }
/// <summary> /// Sorts the complete datamodel according to the rules. /// </summary> /// <remarks> /// Sorts the complete datamodel according to the following rules: /// <ul> /// <li>Nodes at one level are sorted by name, that is prefix + local name</li> /// <li>Starting at the root node the children and qualifier are sorted recursively, /// which the following exceptions.</li> /// <li>Sorting will not be used for arrays.</li> /// <li>Within qualifier "xml:lang" and/or "rdf:type" stay at the top in that order, /// all others are sorted.</li> /// </ul> /// </remarks> public virtual void Sort() { // sort qualifier if (HasQualifier()) { XMPNode[] quals = new XMPNode[GetQualifier().Count]; GetQualifier().CopyTo(quals, 0); int sortFrom = 0; while (quals.Length > sortFrom && (XMPConst.XML_LANG.Equals(quals[sortFrom].GetName()) || "rdf:type".Equals(quals[sortFrom].GetName()))) { quals[sortFrom].Sort(); sortFrom++; } Array.Sort(quals, sortFrom, quals.Length - sortFrom); for (int j = 0; j < quals.Length; j++) { qualifier[j] = quals[j]; quals[j].Sort(); } } // sort children if (HasChildren()) { if (!GetOptions().IsArray()) { ArrayList.Adapter(children).Sort(); } IEnumerator it = IterateChildren(); while (it.MoveNext()) { if (it.Current != null) { ((XMPNode)it.Current).Sort(); } } } }
/// <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> /// 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="iText.Kernel.XMP.XMPException"></exception> private static int LookupQualSelector(XMPNode arrayNode, String qualName, String qualValue, int aliasForm) { if (XML_LANG.Equals(qualName)) { qualValue = iText.Kernel.XMP.Impl.Utils.NormalizeLangValue(qualValue); int index = XMPNodeUtils.LookupLanguageItem(arrayNode, qualValue); if (index < 0 && (aliasForm & AliasOptions.PROP_ARRAY_ALT_TEXT) > 0) { XMPNode langNode = new XMPNode(ARRAY_ITEM_NAME, null); XMPNode xdefault = new XMPNode(XML_LANG, X_DEFAULT, null); langNode.AddQualifier(xdefault); arrayNode.AddChild(1, langNode); return(1); } else { return(index); } } else { for (int index = 1; index < arrayNode.GetChildrenLength(); index++) { XMPNode currItem = arrayNode.GetChild(index); for (IEnumerator it = currItem.IterateQualifier(); it.MoveNext();) { XMPNode qualifier = (XMPNode)it.Current; if (qualName.Equals(qualifier.GetName()) && qualValue.Equals(qualifier.GetValue() )) { return(index); } } } return(-1); } }
/// <summary>Looks for the appropriate language item in a text alternative array.item /// </summary> /// <param name="arrayNode">an array node</param> /// <param name="language">the requested language</param> /// <returns>Returns the index if the language has been found, -1 otherwise.</returns> /// <exception cref="iText.Kernel.XMP.XMPException"/> internal static int LookupLanguageItem(XMPNode arrayNode, String language) { if (!arrayNode.GetOptions().IsArray()) { throw new XMPException("Language item must be used on array", XMPError.BADXPATH); } for (int index = 1; index <= arrayNode.GetChildrenLength(); index++) { XMPNode child = arrayNode.GetChild(index); if (!child.HasQualifier() || !XML_LANG.Equals(child.GetQualifier(1).GetName())) { continue; } else { if (language.Equals(child.GetQualifier(1).GetValue())) { return(index); } } } return(-1); }
/// <summary> /// The internals for setProperty() and related calls, used after the node is /// found or created. /// </summary> /// <param name="node">the newly created node</param> /// <param name="value">the node value, can be <code>null</code></param> /// <param name="newOptions">options for the new node, must not be <code>null</code>. /// </param> /// <param name="deleteExisting">flag if the existing value is to be overwritten</param> /// <exception cref="iText.Kernel.XMP.XMPException">thrown if options and value do not correspond</exception> internal virtual void SetNode(XMPNode node, Object value, PropertyOptions newOptions , bool deleteExisting) { if (deleteExisting) { node.Clear(); } // its checked by setOptions(), if the merged result is a valid options set node.GetOptions().MergeWith(newOptions); if (!node.GetOptions().IsCompositeProperty()) { // This is setting the value of a leaf node. XMPNodeUtils.SetNodeValue(node, value); } else { if (value != null && value.ToString().Length > 0) { throw new XMPException("Composite nodes can't have values", XMPError.BADXPATH); } node.RemoveChildren(); } }
/// <summary> /// Creates a property info object from an <code>XMPNode</code>. </summary> /// <param name="node"> an <code>XMPNode</code> </param> /// <param name="baseNs"> the base namespace to report </param> /// <param name="path"> the full property path </param> /// <returns> Returns a <code>XMPProperty</code>-object that serves representation of the node. </returns> protected internal virtual XMPPropertyInfo CreatePropertyInfo(XMPNode node, String baseNS, String path) { String value = node.GetOptions().IsSchemaNode() ? null : node.GetValue(); return(new XMPPropertyInfoImpl(node, baseNS, path, value)); }
public _XMPProperty_428(XMPNode itemNode) { this.itemNode = itemNode; }
/// <summary> /// <ol> /// <li>Look for an exact match with the specific language. /// </summary> /// <remarks> /// <ol> /// <li>Look for an exact match with the specific language. /// <li>If a generic language is given, look for partial matches. /// <li>Look for an "x-default"-item. /// <li>Choose the first item. /// </ol> /// </remarks> /// <param name="arrayNode">the alt text array node</param> /// <param name="genericLang">the generic language</param> /// <param name="specificLang">the specific language</param> /// <returns> /// Returns the kind of match as an Integer and the found node in an /// array. /// </returns> /// <exception cref="iText.Kernel.XMP.XMPException"/> internal static Object[] ChooseLocalizedText(XMPNode arrayNode, String genericLang , String specificLang) { // See if the array has the right form. Allow empty alt arrays, // that is what parsing returns. if (!arrayNode.GetOptions().IsArrayAltText()) { throw new XMPException("Localized text array is not alt-text", XMPError.BADXPATH); } else { if (!arrayNode.HasChildren()) { return(new Object[] { XMPNodeUtils.CLT_NO_VALUES, null }); } } int foundGenericMatches = 0; XMPNode resultNode = null; XMPNode xDefault = null; // Look for the first partial match with the generic language. for (IEnumerator it = arrayNode.IterateChildren(); it.MoveNext();) { XMPNode currItem = (XMPNode)it.Current; // perform some checks on the current item if (currItem.GetOptions().IsCompositeProperty()) { throw new XMPException("Alt-text array item is not simple", XMPError.BADXPATH); } else { if (!currItem.HasQualifier() || !XML_LANG.Equals(currItem.GetQualifier(1).GetName ())) { throw new XMPException("Alt-text array item has no language qualifier", XMPError. BADXPATH); } } String currLang = currItem.GetQualifier(1).GetValue(); // Look for an exact match with the specific language. if (specificLang.Equals(currLang)) { return(new Object[] { XMPNodeUtils.CLT_SPECIFIC_MATCH, currItem }); } else { if (genericLang != null && currLang.StartsWith(genericLang)) { if (resultNode == null) { resultNode = currItem; } // ! Don't return/break, need to look for other matches. foundGenericMatches++; } else { if (X_DEFAULT.Equals(currLang)) { xDefault = currItem; } } } } // evaluate loop if (foundGenericMatches == 1) { return(new Object[] { XMPNodeUtils.CLT_SINGLE_GENERIC, resultNode }); } else { if (foundGenericMatches > 1) { return(new Object[] { XMPNodeUtils.CLT_MULTIPLE_GENERIC, resultNode }); } else { if (xDefault != null) { return(new Object[] { XMPNodeUtils.CLT_XDEFAULT, xDefault }); } else { // Everything failed, choose the first item. return(new Object[] { XMPNodeUtils.CLT_FIRST_ITEM, arrayNode.GetChild(1) }); } } } }
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); } }
// EMPTY /// <summary>Find or create a schema node if <code>createNodes</code> is false and</summary> /// <param name="tree">the root of the xmp tree.</param> /// <param name="namespaceURI">a namespace</param> /// <param name="createNodes"> /// a flag indicating if the node shall be created if not found. /// <em>Note:</em> The namespace must be registered prior to this call. /// </param> /// <returns> /// Returns the schema node if found, <code>null</code> otherwise. /// Note: If <code>createNodes</code> is <code>true</code>, it is <b>always</b> /// returned a valid node. /// </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 FindSchemaNode(XMPNode tree, String namespaceURI, bool createNodes ) { return(FindSchemaNode(tree, namespaceURI, null, createNodes)); }
public _XMPProperty_703(Object value, XMPNode propNode) { this.value = value; this.propNode = propNode; }
/// <summary> /// After processing by ExpandXPath, a step can be of these forms: /// <ul> /// <li>qualName - A top level property or struct field. /// </summary> /// <remarks> /// After processing by ExpandXPath, a step can be of these forms: /// <ul> /// <li>qualName - A top level property or struct field. /// <li>[index] - An element of an array. /// <li>[last()] - The last element of an array. /// <li>[qualName="value"] - An element in an array of structs, chosen by a field value. /// <li>[?qualName="value"] - An element in an array, chosen by a qualifier value. /// <li>?qualName - A general qualifier. /// </ul> /// Find the appropriate child node, resolving aliases, and optionally creating nodes. /// </remarks> /// <param name="parentNode">the node to start to start from</param> /// <param name="nextStep">the xpath segment</param> /// <param name="createNodes"></param> /// <returns>returns the found or created XMPPath node</returns> /// <exception cref="iText.Kernel.XMP.XMPException"></exception> private static XMPNode FollowXPathStep(XMPNode parentNode, XMPPathSegment nextStep , bool createNodes) { XMPNode nextNode = null; int index = 0; int stepKind = nextStep.GetKind(); if (stepKind == XMPPath.STRUCT_FIELD_STEP) { nextNode = FindChildNode(parentNode, nextStep.GetName(), createNodes); } else { if (stepKind == XMPPath.QUALIFIER_STEP) { nextNode = FindQualifierNode(parentNode, nextStep.GetName().Substring(1), createNodes ); } else { // This is an array indexing step. First get the index, then get the node. if (!parentNode.GetOptions().IsArray()) { throw new XMPException("Indexing applied to non-array", XMPError.BADXPATH); } if (stepKind == XMPPath.ARRAY_INDEX_STEP) { index = FindIndexedItem(parentNode, nextStep.GetName(), createNodes); } else { if (stepKind == XMPPath.ARRAY_LAST_STEP) { index = parentNode.GetChildrenLength(); } else { if (stepKind == XMPPath.FIELD_SELECTOR_STEP) { String[] result = Utils.SplitNameAndValue(nextStep.GetName()); String fieldName = result[0]; String fieldValue = result[1]; index = LookupFieldSelector(parentNode, fieldName, fieldValue); } else { if (stepKind == XMPPath.QUAL_SELECTOR_STEP) { String[] result = Utils.SplitNameAndValue(nextStep.GetName()); String qualName = result[0]; String qualValue = result[1]; index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.GetAliasForm ()); } else { throw new XMPException("Unknown array indexing step in FollowXPathStep", XMPError .INTERNALFAILURE); } } } } if (1 <= index && index <= parentNode.GetChildrenLength()) { nextNode = parentNode.GetChild(index); } } } return(nextNode); }
/// <summary>Constructor for an empty metadata object.</summary> public XMPMetaImpl() { // create root node tree = new XMPNode(null, null, null); }
/// <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); }
/// <summary>Visit all of the top level nodes looking for aliases.</summary> /// <remarks> /// Visit all of the top level nodes looking for aliases. If there is /// no base, transplant the alias subtree. If there is a base and strict /// aliasing is on, make sure the alias and base subtrees match. /// </remarks> /// <param name="tree">the root of the metadata tree</param> /// <param name="options">th parsing options</param> /// <exception cref="iText.Kernel.XMP.XMPException">Forwards XMP errors</exception> private static void MoveExplicitAliases(XMPNode tree, ParseOptions options) { if (!tree.GetHasAliases()) { return; } tree.SetHasAliases(false); bool strictAliasing = options.GetStrictAliasing(); IEnumerator schemaIt = tree.GetUnmodifiableChildren().GetEnumerator(); while (schemaIt.MoveNext()) { XMPNode currSchema = (XMPNode)schemaIt.Current; if (currSchema == null) { continue; } if (!currSchema.GetHasAliases()) { continue; } List <XMPNode> currPropsToRemove = new List <XMPNode>(); IEnumerator propertyIt = currSchema.IterateChildren(); while (propertyIt.MoveNext()) { XMPNode currProp = (XMPNode)propertyIt.Current; if (currProp == null) { continue; } if (!currProp.IsAlias()) { continue; } currProp.SetAlias(false); // Find the base path, look for the base schema and root node. XMPAliasInfo info = XMPMetaFactory.GetSchemaRegistry().FindAlias(currProp.GetName()); if (info != null) { // find or create schema XMPNode baseSchema = XMPNodeUtils.FindSchemaNode(tree, info.GetNamespace(), null, true); baseSchema.SetImplicit(false); XMPNode baseNode = XMPNodeUtils.FindChildNode(baseSchema, info.GetPrefix() + info.GetPropName(), false); if (baseNode == null) { if (info.GetAliasForm().IsSimple()) { // A top-to-top alias, transplant the property. // change the alias property name to the base name string qname = info.GetPrefix() + info.GetPropName(); currProp.SetName(qname); baseSchema.AddChild(currProp); } else { // An alias to an array item, // create the array and transplant the property. baseNode = new XMPNode(info.GetPrefix() + info.GetPropName(), info.GetAliasForm().ToPropertyOptions()); baseSchema.AddChild(baseNode); TransplantArrayItemAlias(currProp, baseNode); } currPropsToRemove.Add(currProp); } else if (info.GetAliasForm().IsSimple()) { // The base node does exist and this is a top-to-top alias. // Check for conflicts if strict aliasing is on. // Remove and delete the alias subtree. if (strictAliasing) { CompareAliasedSubtrees(currProp, baseNode, true); } currPropsToRemove.Add(currProp); } else { // This is an alias to an array item and the array exists. // Look for the aliased item. // Then transplant or check & delete as appropriate. XMPNode itemNode = null; if (info.GetAliasForm().IsArrayAltText()) { int xdIndex = XMPNodeUtils.LookupLanguageItem(baseNode, XMPConst.X_DEFAULT); if (xdIndex != -1) { itemNode = baseNode.GetChild(xdIndex); } } else if (baseNode.HasChildren()) { itemNode = baseNode.GetChild(1); } if (itemNode == null) { TransplantArrayItemAlias(currProp, baseNode); } else { if (strictAliasing) { CompareAliasedSubtrees(currProp, itemNode, true); } } currPropsToRemove.Add(currProp); } } } foreach (XMPNode o in currPropsToRemove) { currSchema.RemoveChild(o); } currPropsToRemove.Clear(); currSchema.SetHasAliases(false); } }
/// <summary> /// Evaluates a raw node value to the given value type, apply special /// conversions for defined types in XMP. /// </summary> /// <param name="valueType">an int indicating the value type</param> /// <param name="propNode">the node containing the value</param> /// <returns>Returns a literal value for the node.</returns> /// <exception cref="iText.Kernel.XMP.XMPException"> /// if the value of <code>propNode</code> is <code>null</code> or empty or the conversion fails. /// </exception> private Object EvaluateNodeValue(int valueType, XMPNode propNode) { Object value; String rawValue = propNode.GetValue(); switch (valueType) { case VALUE_BOOLEAN: { value = XMPUtils.ConvertToBoolean(rawValue); break; } case VALUE_INTEGER: { value = XMPUtils.ConvertToInteger(rawValue); break; } case VALUE_LONG: { value = XMPUtils.ConvertToLong(rawValue); break; } case VALUE_DOUBLE: { value = XMPUtils.ConvertToDouble(rawValue); break; } case VALUE_DATE: { value = XMPUtils.ConvertToDate(rawValue); break; } case VALUE_CALENDAR: { XMPDateTime dt = XMPUtils.ConvertToDate(rawValue); value = dt.GetCalendar(); break; } case VALUE_BASE64: { value = XMPUtils.DecodeBase64(rawValue); break; } case VALUE_STRING: default: { // leaf values return empty string instead of null // for the other cases the converter methods provides a "null" // value. // a default value can only occur if this method is made public. value = rawValue != null || propNode.GetOptions().IsCompositeProperty() ? rawValue : ""; break; } } return value; }
//------------------------------------------------------------------------------ private methods /// <summary>Dumps this node and its qualifier and children recursively.</summary> /// <remarks> /// Dumps this node and its qualifier and children recursively. /// <em>Note:</em> It creats empty options on every node. /// </remarks> /// <param name="result">the buffer to append the dump.</param> /// <param name="recursive">Flag is qualifier and child nodes shall be rendered too</param> /// <param name="indent">the current indent level.</param> /// <param name="index">the index within the parent node (important for arrays)</param> private void DumpNode(StringBuilder result, bool recursive, int indent, int index ) { // write indent for (int i = 0; i < indent; i++) { result.Append('\t'); } // render Node if (parent != null) { if (GetOptions().IsQualifier()) { result.Append('?'); result.Append(name); } else { if (GetParent().GetOptions().IsArray()) { result.Append('['); result.Append(index); result.Append(']'); } else { result.Append(name); } } } else { // applies only to the root node result.Append("ROOT NODE"); if (name != null && name.Length > 0) { // the "about" attribute result.Append(" ("); result.Append(name); result.Append(')'); } } if (value != null && value.Length > 0) { result.Append(" = \""); result.Append(value); result.Append('"'); } // render options if at least one is set if (GetOptions().ContainsOneOf(unchecked ((int)(0xffffffff)))) { result.Append("\t("); result.Append(GetOptions().ToString()); result.Append(" : "); result.Append(GetOptions().GetOptionsString()); result.Append(')'); } result.Append('\n'); // render qualifier if (recursive && HasQualifier()) { XMPNode[] quals = new XMPNode[GetQualifier().Count]; GetQualifier().CopyTo(quals, 0); int i = 0; while (quals.Length > i && (XMPConst.XML_LANG.Equals(quals[i].GetName()) || "rdf:type" .Equals(quals[i].GetName()))) { i++; } System.Array.Sort(quals, i, quals.Length); for (i = 0; i < quals.Length; i++) { iText.Kernel.XMP.Impl.XMPNode qualifier = quals[i]; qualifier.DumpNode(result, recursive, indent + 2, i + 1); } } // render children if (recursive && HasChildren()) { XMPNode[] children = new XMPNode[GetChildren().Count]; GetChildren().CopyTo(children, 0); if (!GetOptions().IsArray()) { System.Array.Sort(children); } for (int i = 0; i < children.Length; i++) { iText.Kernel.XMP.Impl.XMPNode child = children[i]; child.DumpNode(result, recursive, indent + 1, i + 1); } } }
/// <summary>Constructor for a cloned metadata tree.</summary> /// <param name="tree"> /// an prefilled metadata tree which fulfills all /// <code>XMPNode</code> contracts. /// </param> public XMPMetaImpl(XMPNode tree) { this.tree = tree; }
/// <summary>Performs a deep clone of the XMPMeta-object</summary> /// <seealso cref="System.Object.Clone()"/> public virtual Object Clone() { XMPNode clonedTree = (XMPNode)tree.Clone(); return new XMPMetaImpl(clonedTree); }