GetChild() public method

public GetChild ( int index ) : XmpNode
index int an index [1..size]
return XmpNode
Beispiel #1
0
        /// <summary>
        /// Undo the denormalization performed by the XMP used in Acrobat 5.<br>
        /// If a Dublin Core array had only one item, it was serialized as a simple
        /// property. <br>
        /// The <code>xml:lang</code> attribute was dropped from an
        /// <code>alt-text</code> item if the language was <code>x-default</code>.
        /// </summary>
        /// <param name="dcSchema"> the DC schema node </param>
        /// <exception cref="XmpException"> Thrown if normalization fails </exception>
        private static void NormalizeDcArrays(XmpNode dcSchema)
        {
            for (int i = 1; i <= dcSchema.ChildrenLength; i++)
            {
                XmpNode currProp = dcSchema.GetChild(i);

                PropertyOptions arrayForm = (PropertyOptions)_dcArrayForms[currProp.Name];
                if (arrayForm == null)
                {
                    continue;
                }
                if (currProp.Options.Simple)
                {
                    // create a new array and add the current property as child,
                    // if it was formerly simple
                    XmpNode newArray = new XmpNode(currProp.Name, arrayForm);
                    currProp.Name = XmpConst.ARRAY_ITEM_NAME;
                    newArray.AddChild(currProp);
                    dcSchema.ReplaceChild(i, newArray);

                    // fix language alternatives
                    if (arrayForm.ArrayAltText && !currProp.Options.HasLanguage)
                    {
                        XmpNode newLang = new XmpNode(XmpConst.XML_LANG, XmpConst.X_DEFAULT, null);
                        currProp.AddQualifier(newLang);
                    }
                }
                else
                {
                    // clear array options and add corrected array form if it has been an array before
                    currProp.Options.SetOption(
                        PropertyOptions.ARRAY | PropertyOptions.ARRAY_ORDERED | PropertyOptions.ARRAY_ALTERNATE |
                        PropertyOptions.ARRAY_ALT_TEXT, false);
                    currProp.Options.MergeWith(arrayForm);

                    if (arrayForm.ArrayAltText)
                    {
                        // applying for "dc:description", "dc:rights", "dc:title"
                        RepairAltText(currProp);
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void FixupQualifiedNode(XmpNode xmpParent) {
            Debug.Assert(xmpParent.Options.Struct && xmpParent.HasChildren());

            XmpNode 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", XmpError.BADXMP);
                }
                XmpNode langQual = valueNode.GetQualifier(1);
                valueNode.RemoveQualifier(langQual);
                xmpParent.AddQualifier(langQual);
            }

            // Start the remaining copy after the xml:lang qualifier.		
            for (int i = 1; i <= valueNode.QualifierLength; i++) {
                XmpNode 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 (int i = 2; i <= xmpParent.ChildrenLength; i++) {
                XmpNode qualifier = xmpParent.GetChild(i);
                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.Struct || xmpParent.HasValueChild);

            xmpParent.HasValueChild = false;
            xmpParent.Options.Struct = false;
            xmpParent.Options.MergeWith(valueNode.Options);
            xmpParent.Value = valueNode.Value;

            xmpParent.RemoveChildren();
            for (IEnumerator it = valueNode.IterateChildren(); it.MoveNext();) {
                XmpNode child = (XmpNode) it.Current;
                xmpParent.AddChild(child);
            }
        }
Beispiel #3
0
        /// <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="XmpException"> </exception>
        internal static int LookupLanguageItem(XmpNode arrayNode, string language) {
            if (!arrayNode.Options.Array) {
                throw new XmpException("Language item must be used on array", XmpError.BADXPATH);
            }

            for (int index = 1; index <= arrayNode.ChildrenLength; index++) {
                XmpNode child = arrayNode.GetChild(index);
                if (!child.HasQualifier() || !XML_LANG.Equals(child.GetQualifier(1).Name)) {
                    continue;
                }
                if (language.Equals(child.GetQualifier(1).Value)) {
                    return index;
                }
            }

            return -1;
        }
Beispiel #4
0
        /// <summary>
        /// <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>
        /// </summary>
        /// <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="XmpException"> </exception>
        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.Options.ArrayAltText) {
                throw new XmpException("Localized text array is not alt-text", XmpError.BADXPATH);
            }
            if (!arrayNode.HasChildren()) {
                return new object[] {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 == null || currItem.Options == null || currItem.Options.CompositeProperty) {
                    throw new XmpException("Alt-text array item is not simple", XmpError.BADXPATH);
                }
                if (!currItem.HasQualifier() || !XML_LANG.Equals(currItem.GetQualifier(1).Name)) {
                    throw new XmpException("Alt-text array item has no language qualifier", XmpError.BADXPATH);
                }

                string currLang = currItem.GetQualifier(1).Value;

                // Look for an exact match with the specific language.
                if (specificLang.Equals(currLang)) {
                    return new object[] {CLT_SPECIFIC_MATCH, currItem};
                }
                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[] {CLT_SINGLE_GENERIC, resultNode};
            }
            if (foundGenericMatches > 1) {
                return new object[] {CLT_MULTIPLE_GENERIC, resultNode};
            }
            if (xDefault != null) {
                return new object[] {CLT_XDEFAULT, xDefault};
            }
            {
                // Everything failed, choose the first item.
                return new object[] {CLT_FIRST_ITEM, arrayNode.GetChild(1)};
            }
        }
Beispiel #5
0
        /// <summary>
        /// Make sure the x-default item is first. Touch up &quot;single value&quot;
        /// arrays that have a default plus one real language. This case should have
        /// the same value for both items. Older Adobe apps were hardwired to only
        /// use the &quot;x-default&quot; item, so we copy that value to the other
        /// item.
        /// </summary>
        /// <param name="arrayNode">
        ///            an alt text array node </param>
        internal static void NormalizeLangArray(XmpNode arrayNode) {
            if (!arrayNode.Options.ArrayAltText) {
                return;
            }

            // check if node with x-default qual is first place
            for (int i = 2; i <= arrayNode.ChildrenLength; i++) {
                XmpNode child = arrayNode.GetChild(i);
                if (child.HasQualifier() && X_DEFAULT.Equals(child.GetQualifier(1).Value)) {
                    // move node to first place
                    try {
                        arrayNode.RemoveChild(i);
                        arrayNode.AddChild(1, child);
                    }
                    catch (XmpException) {
                        // cannot occur, because same child is removed before
                        Debug.Assert(false);
                    }

                    if (i == 2) {
                        arrayNode.GetChild(2).Value = child.Value;
                    }
                    break;
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// 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.
        /// </summary>
        /// <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, uint aliasForm) {
            if (XML_LANG.Equals(qualName)) {
                qualValue = Utils.NormalizeLangValue(qualValue);
                int index = 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;
                }
                return index;
            }
            for (int index = 1; index < arrayNode.ChildrenLength; index++) {
                XmpNode currItem = arrayNode.GetChild(index);

                for (IEnumerator it = currItem.IterateQualifier(); it.MoveNext();) {
                    XmpNode qualifier = (XmpNode) it.Current;
                    if (qualifier != null && qualName.Equals(qualifier.Name) && qualValue.Equals(qualifier.Value)) {
                        return index;
                    }
                }
            }
            return -1;
        }
Beispiel #7
0
        /// <summary>
        /// Searches for a field selector in a node:
        /// [fieldName="value] - an element in an array of structs, chosen by a field value.
        /// No implicit nodes are created by field selectors. 
        /// </summary>
        /// <param name="arrayNode"> </param>
        /// <param name="fieldName"> </param>
        /// <param name="fieldValue"> </param>
        /// <returns> Returns the index of the field if found, otherwise -1. </returns>
        /// <exception cref="XmpException">  </exception>
        private static int LookupFieldSelector(XmpNode arrayNode, string fieldName, string fieldValue) {
            int result = -1;

            for (int index = 1; index <= arrayNode.ChildrenLength && result < 0; index++) {
                XmpNode currItem = arrayNode.GetChild(index);

                if (!currItem.Options.Struct) {
                    throw new XmpException("Field selector must be used on array of struct", XmpError.BADXPATH);
                }

                for (int f = 1; f <= currItem.ChildrenLength; f++) {
                    XmpNode currField = currItem.GetChild(f);
                    if (!fieldName.Equals(currField.Name)) {
                        continue;
                    }
                    if (fieldValue.Equals(currField.Value)) {
                        result = index;
                        break;
                    }
                }
            }

            return result;
        }
Beispiel #8
0
        /// <summary>
        /// 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.
        /// </summary>
        /// <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="XmpException">  </exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes) {
            XmpNode nextNode = null;
            uint stepKind = nextStep.Kind;

            if (stepKind == XmpPath.STRUCT_FIELD_STEP) {
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
            }
            else if (stepKind == XmpPath.QUALIFIER_STEP) {
                nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
            }
            else {
                // This is an array indexing step. First get the index, then get the node.
                int index;

                if (!parentNode.Options.Array) {
                    throw new XmpException("Indexing applied to non-array", XmpError.BADXPATH);
                }

                if (stepKind == XmpPath.ARRAY_INDEX_STEP) {
                    index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                }
                else if (stepKind == XmpPath.ARRAY_LAST_STEP) {
                    index = parentNode.ChildrenLength;
                }
                else if (stepKind == XmpPath.FIELD_SELECTOR_STEP) {
                    string[] result = Utils.SplitNameAndValue(nextStep.Name);
                    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.Name);
                    string qualName = result[0];
                    string qualValue = result[1];
                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                }
                else {
                    throw new XmpException("Unknown array indexing step in FollowXPathStep",
                                           XmpError.INTERNALFAILURE);
                }

                if (1 <= index && index <= parentNode.ChildrenLength) {
                    nextNode = parentNode.GetChild(index);
                }
            }

            return nextNode;
        }
Beispiel #9
0
        /// <summary>
        /// Undo the denormalization performed by the XMP used in Acrobat 5.<br> 
        /// If a Dublin Core array had only one item, it was serialized as a simple
        /// property. <br>
        /// The <code>xml:lang</code> attribute was dropped from an
        /// <code>alt-text</code> item if the language was <code>x-default</code>.
        /// </summary>
        /// <param name="dcSchema"> the DC schema node </param>
        /// <exception cref="XmpException"> Thrown if normalization fails </exception>
        private static void NormalizeDcArrays(XmpNode dcSchema) {
            for (int i = 1; i <= dcSchema.ChildrenLength; i++) {
                XmpNode currProp = dcSchema.GetChild(i);

                PropertyOptions arrayForm = (PropertyOptions) _dcArrayForms[currProp.Name];
                if (arrayForm == null) {
                    continue;
                }
                if (currProp.Options.Simple) {
                    // create a new array and add the current property as child, 
                    // if it was formerly simple 
                    XmpNode newArray = new XmpNode(currProp.Name, arrayForm);
                    currProp.Name = XmpConst.ARRAY_ITEM_NAME;
                    newArray.AddChild(currProp);
                    dcSchema.ReplaceChild(i, newArray);

                    // fix language alternatives
                    if (arrayForm.ArrayAltText && !currProp.Options.HasLanguage) {
                        XmpNode newLang = new XmpNode(XmpConst.XML_LANG, XmpConst.X_DEFAULT, null);
                        currProp.AddQualifier(newLang);
                    }
                }
                else {
                    // clear array options and add corrected array form if it has been an array before
                    currProp.Options.SetOption(
                        PropertyOptions.ARRAY | PropertyOptions.ARRAY_ORDERED | PropertyOptions.ARRAY_ALTERNATE |
                        PropertyOptions.ARRAY_ALT_TEXT, false);
                    currProp.Options.MergeWith(arrayForm);

                    if (arrayForm.ArrayAltText) {
                        // applying for "dc:description", "dc:rights", "dc:title"
                        RepairAltText(currProp);
                    }
                }
            }
        }