📄 xmpnodeutils.java
字号:
} 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; } /** * Find or create a qualifier node under a given parent node. Returns a pointer to the * qualifier node, and optionally an iterator for the node's position in * the parent's vector of qualifiers. The iterator is unchanged if no qualifier node (null) * is returned. * <em>Note:</em> On entry, the qualName parameter must not have the leading '?' from the * XMPPath step. * * @param parent the parent XMPNode * @param qualName the qualifier name * @param createNodes flag if nodes shall be created * @return Returns the qualifier node if found or created, <code>null</code> otherwise. * @throws XMPException */ private static XMPNode findQualifierNode(XMPNode parent, String qualName, boolean createNodes) throws XMPException { assert !qualName.startsWith("?"); XMPNode qualNode = parent.findQualifierByName(qualName); if (qualNode == null && createNodes) { qualNode = new XMPNode(qualName, null); qualNode.setImplicit(true); parent.addQualifier(qualNode); } return qualNode; } /** * @param arrayNode an array node * @param segment the segment containing the array index * @param createNodes flag if new nodes are allowed to be created. * @return Returns the index or index = -1 if not found * @throws XMPException Throws Exceptions */ private static int findIndexedItem(XMPNode arrayNode, String segment, boolean createNodes) throws XMPException { int index = 0; try { segment = segment.substring(1, segment.length() - 1); index = Integer.parseInt(segment); if (index < 1) { throw new XMPException("Array index must be larger than zero", XMPError.BADXPATH); } } catch (NumberFormatException e) { throw new XMPException("Array index not digits.", XMPError.BADXPATH); } if (index == arrayNode.getChildrenLength() + 1 && createNodes) { // Append a new last + 1 node. XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, null); newItem.setImplicit(true); arrayNode.addChild(newItem); } // Don't throw here for a too large index. setProperty() will throw, // getProperty() will not. if (index > arrayNode.getChildrenLength()) { index = -1; } return index; } /** * 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. * * @param arrayNode * @param fieldName * @param fieldValue * @return Returns the index of the field if found, otherwise -1. * @throws XMPException */ private static int lookupFieldSelector(XMPNode arrayNode, String fieldName, String fieldValue) throws XMPException { int result = -1; for (int index = 1; index <= arrayNode.getChildrenLength() && result < 0; index++) { XMPNode currItem = arrayNode.getChild(index); if (!currItem.getOptions().isStruct()) { throw new XMPException("Field selector must be used on array of struct", XMPError.BADXPATH); } for (int f = 1; f <= currItem.getChildrenLength(); f++) { XMPNode currField = currItem.getChild(f); if (!fieldName.equals(currField.getName())) { continue; } if (fieldValue.equals(currField.getValue())) { result = index; break; } } } return result; } /** * 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. * * @param arrayNode an array node * @param qualName the qualifier name * @param qualValue the qualifier value * @param aliasForm in case the qual selector results from an alias, * an x-default node is created if there has not been one. * @return Returns the index of th * @throws XMPException */ private static int lookupQualSelector(XMPNode arrayNode, String qualName, String qualValue, int aliasForm) throws XMPException { if (XML_LANG.equals(qualName)) { qualValue = 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 (Iterator it = currItem.iterateQualifier(); it.hasNext();) { XMPNode qualifier = (XMPNode) it.next(); if (qualName.equals(qualifier.getName()) && qualValue.equals(qualifier.getValue())) { return index; } } } return -1; } } /** * Make sure the x-default item is first. Touch up "single value" * 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 "x-default" item, so we copy that value to the other * item. * * @param arrayNode * an alt text array node */ static void normalizeLangArray(XMPNode arrayNode) { if (!arrayNode.getOptions().isArrayAltText()) { return; } // check if node with x-default qual is first place for (int i = 2; i <= arrayNode.getChildrenLength(); i++) { XMPNode child = arrayNode.getChild(i); if (child.hasQualifier() && X_DEFAULT.equals(child.getQualifier(1).getValue())) { // move node to first place try { arrayNode.removeChild(i); arrayNode.addChild(1, child); } catch (XMPException e) { // cannot occur, because same child is removed before assert false; } if (i == 2) { arrayNode.getChild(2).setValue(child.getValue()); } break; } } } /** * See if an array is an alt-text array. If so, make sure the x-default item * is first. * * @param arrayNode * the array node to check if its an alt-text array */ static void detectAltText(XMPNode arrayNode) { if (arrayNode.getOptions().isArrayAlternate() && arrayNode.hasChildren()) { boolean isAltText = false; for (Iterator it = arrayNode.iterateChildren(); it.hasNext();) { XMPNode child = (XMPNode) it.next(); if (child.getOptions().getHasLanguage()) { isAltText = true; break; } } if (isAltText) { arrayNode.getOptions().setArrayAltText(true); normalizeLangArray(arrayNode); } } } /** * Appends a language item to an alt text array. * * @param arrayNode the language array * @param itemLang the language of the item * @param itemValue the content of the item * @throws XMPException Thrown if a duplicate property is added */ static void appendLangItem(XMPNode arrayNode, String itemLang, String itemValue) throws XMPException { XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, itemValue, null); XMPNode langQual = new XMPNode(XML_LANG, itemLang, null); newItem.addQualifier(langQual); if (!X_DEFAULT.equals(langQual.getValue())) { arrayNode.addChild(newItem); } else { arrayNode.addChild(1, newItem); } } /** * <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> * * @param arrayNode * the alt text array node * @param genericLang * the generic language * @param specificLang * the specific language * @return Returns the kind of match as an Integer and the found node in an * array. * * @throws XMPException */ static Object[] chooseLocalizedText(XMPNode arrayNode, String genericLang, String specificLang) throws XMPException { // 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[] { new Integer(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 (Iterator it = arrayNode.iterateChildren(); it.hasNext();) { XMPNode currItem = (XMPNode) it.next(); // 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[] { new Integer(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[] { new Integer(XMPNodeUtils.CLT_SINGLE_GENERIC), resultNode }; } else if (foundGenericMatches > 1) { return new Object[] { new Integer(XMPNodeUtils.CLT_MULTIPLE_GENERIC), resultNode }; } else if (xDefault != null) { return new Object[] { new Integer(XMPNodeUtils.CLT_XDEFAULT), xDefault }; } else { // Everything failed, choose the first item. return new Object[] { new Integer(XMPNodeUtils.CLT_FIRST_ITEM), arrayNode.getChild(1) }; } } /** * Looks for the appropriate language item in a text alternative array.item * * @param arrayNode * an array node * @param language * the requested language * @return Returns the index if the language has been found, -1 otherwise. * @throws XMPException */ static int lookupLanguageItem(XMPNode arrayNode, String language) throws XMPException { 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; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -