/// <exception cref="XmpException"/>
        public 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?Utils.NormalizeLangValue(genericLang) : null;

            specificLang = Utils.NormalizeLangValue(specificLang);
            var arrayPath = XmpPathParser.ExpandXPath(schemaNs, altTextName);
            // Find the array node and set the options if it was just created.
            var arrayNode = XmpNodeUtils.FindNode(_tree, arrayPath, true, new PropertyOptions(PropertyOptions.ArrayFlag | PropertyOptions.ArrayOrderedFlag | PropertyOptions.ArrayAlternateFlag | PropertyOptions.ArrayAltTextFlag));

            if (arrayNode == null)
            {
                throw new XmpException("Failed to find or create array node", XmpErrorCode.BadXPath);
            }
            if (!arrayNode.Options.IsArrayAltText)
            {
                if (!arrayNode.HasChildren && arrayNode.Options.IsArrayAlternate)
                {
                    arrayNode.Options.IsArrayAltText = true;
                }
                else
                {
                    throw new XmpException("Specified property is no alt-text array", XmpErrorCode.BadXPath);
                }
            }
            // Make sure the x-default item, if any, is first.
            var     haveXDefault = false;
            XmpNode xdItem       = null;

            for (var it = arrayNode.IterateChildren(); it.HasNext();)
            {
                var currItem = (XmpNode)it.Next();
                if (!currItem.HasQualifier || !XmpConstants.XmlLang.Equals(currItem.GetQualifier(1).Name))
                {
                    throw new XmpException("Language qualifier must be first", XmpErrorCode.BadXPath);
                }
                if (XmpConstants.XDefault.Equals(currItem.GetQualifier(1).Value))
                {
                    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.
            var result           = XmpNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang);
            var match            = (int)result[0];
            var itemNode         = (XmpNode)result[1];
            var specificXDefault = XmpConstants.XDefault.Equals(specificLang);

            switch (match)
            {
            case XmpNodeUtils.CltNoValues:
            {
                // Create the array items for the specificLang and x-default, with
                // x-default first.
                XmpNodeUtils.AppendLangItem(arrayNode, XmpConstants.XDefault, itemValue);
                haveXDefault = true;
                if (!specificXDefault)
                {
                    XmpNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
                }
                break;
            }

            case XmpNodeUtils.CltSpecificMatch:
            {
                if (!specificXDefault)
                {
                    // Update the specific item, update x-default if it matches the
                    // old value.
                    if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.Value.Equals(itemNode.Value))
                    {
                        xdItem.Value = itemValue;
                    }
                    // ! Do this after the x-default check!
                    itemNode.Value = itemValue;
                }
                else
                {
                    // Update all items whose values match the old x-default value.
                    Debug.Assert(haveXDefault && xdItem == itemNode);
                    for (var it1 = arrayNode.IterateChildren(); it1.HasNext();)
                    {
                        var currItem = (XmpNode)it1.Next();
                        if (currItem == xdItem || !currItem.Value.Equals(xdItem != null ? xdItem.Value : null))
                        {
                            continue;
                        }
                        currItem.Value = itemValue;
                    }
                    // And finally do the x-default item.
                    if (xdItem != null)
                    {
                        xdItem.Value = itemValue;
                    }
                }
                break;
            }

            case XmpNodeUtils.CltSingleGeneric:
            {
                // Update the generic item, update x-default if it matches the old
                // value.
                if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.Value.Equals(itemNode.Value))
                {
                    xdItem.Value = itemValue;
                }
                itemNode.Value = itemValue;
                // ! Do this after
                // the x-default
                // check!
                break;
            }

            case XmpNodeUtils.CltMultipleGeneric:
            {
                // Create the specific language, ignore x-default.
                XmpNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
                if (specificXDefault)
                {
                    haveXDefault = true;
                }
                break;
            }

            case XmpNodeUtils.CltXdefault:
            {
                // Create the specific language, update x-default if it was the only
                // item.
                if (xdItem != null && arrayNode.GetChildrenLength() == 1)
                {
                    xdItem.Value = itemValue;
                }
                XmpNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
                break;
            }

            case XmpNodeUtils.CltFirstItem:
            {
                // 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", XmpErrorCode.InternalFailure);
            }
            }
            // Add an x-default at the front if needed.
            if (!haveXDefault && arrayNode.GetChildrenLength() == 1)
            {
                XmpNodeUtils.AppendLangItem(arrayNode, XmpConstants.XDefault, itemValue);
            }
        }