1f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 2f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ADOBE SYSTEMS INCORPORATED 3f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// Copyright 2006 Adobe Systems Incorporated 4f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// All Rights Reserved 5f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// 6f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 7f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// of the Adobe license agreement accompanying it. 8f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 9f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 10f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpackage com.adobe.xmp.impl; 11f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 12f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.GregorianCalendar; 13f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Iterator; 14f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 15f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPConst; 16f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPDateTime; 17f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPDateTimeFactory; 18f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPError; 19f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPException; 20f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPMetaFactory; 21f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPUtils; 22f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.impl.xpath.XMPPath; 23f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.impl.xpath.XMPPathSegment; 24f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.options.AliasOptions; 25f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.options.PropertyOptions; 26f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 27f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 28f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling/** 29f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Utilities for <code>XMPNode</code>. 30f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 31f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @since Aug 28, 2006 32f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 33f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpublic class XMPNodeUtils implements XMPConst 34f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling{ 35f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 36f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_NO_VALUES = 0; 37f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 38f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_SPECIFIC_MATCH = 1; 39f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 40f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_SINGLE_GENERIC = 2; 41f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 42f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_MULTIPLE_GENERIC = 3; 43f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 44f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_XDEFAULT = 4; 45f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 46f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static final int CLT_FIRST_ITEM = 5; 47f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 48f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 49f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 50f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Private Constructor 51f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 52f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private XMPNodeUtils() 53f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 54f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // EMPTY 55f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 56f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 57f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 58f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 59f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Find or create a schema node if <code>createNodes</code> is false and 60f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 61f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param tree the root of the xmp tree. 62f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param namespaceURI a namespace 63f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes a flag indicating if the node shall be created if not found. 64f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> The namespace must be registered prior to this call. 65f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 66f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the schema node if found, <code>null</code> otherwise. 67f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Note: If <code>createNodes</code> is <code>true</code>, it is <b>always</b> 68f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * returned a valid node. 69f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException An exception is only thrown if an error occurred, not if a 70f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * node was not found. 71f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 72f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static XMPNode findSchemaNode(XMPNode tree, String namespaceURI, 73f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean createNodes) 74f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 75f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 76f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return findSchemaNode(tree, namespaceURI, null, createNodes); 77f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 78f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 79f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 80f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 81f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Find or create a schema node if <code>createNodes</code> is true. 82f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 83f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param tree the root of the xmp tree. 84f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param namespaceURI a namespace 85f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param suggestedPrefix If a prefix is suggested, the namespace is allowed to be registered. 86f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes a flag indicating if the node shall be created if not found. 87f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> The namespace must be registered prior to this call. 88f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 89f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the schema node if found, <code>null</code> otherwise. 90f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Note: If <code>createNodes</code> is <code>true</code>, it is <b>always</b> 91f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * returned a valid node. 92f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException An exception is only thrown if an error occurred, not if a 93f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * node was not found. 94f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 95f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static XMPNode findSchemaNode(XMPNode tree, String namespaceURI, String suggestedPrefix, 96f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean createNodes) 97f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 98f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 99f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling assert tree.getParent() == null; // make sure that its the root 100f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode schemaNode = tree.findChildByName(namespaceURI); 101f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 102f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (schemaNode == null && createNodes) 103f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 104f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling schemaNode = new XMPNode(namespaceURI, 105f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling new PropertyOptions() 106f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling .setSchemaNode(true)); 107f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling schemaNode.setImplicit(true); 108f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 109f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // only previously registered schema namespaces are allowed in the XMP tree. 110f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String prefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(namespaceURI); 111f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (prefix == null) 112f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 113f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (suggestedPrefix != null && suggestedPrefix.length() != 0) 114f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 115f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling prefix = XMPMetaFactory.getSchemaRegistry().registerNamespace(namespaceURI, 116f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling suggestedPrefix); 117f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 118f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 119f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 120f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Unregistered schema namespace URI", 121f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADSCHEMA); 122f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 123f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 124f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 125f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling schemaNode.setValue(prefix); 126f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 127f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tree.addChild(schemaNode); 128f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 129f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 130f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return schemaNode; 131f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 132f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 133f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 134f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 135f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Find or create a child node under a given parent node. If the parent node is no 136f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Returns the found or created child node. 137f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 138f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param parent 139f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the parent node 140f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param childName 141f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the node name to find 142f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes 143f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * flag, if new nodes shall be created. 144f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the found or created node or <code>null</code>. 145f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if 146f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 147f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static XMPNode findChildNode(XMPNode parent, String childName, boolean createNodes) 148f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 149f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 150f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!parent.getOptions().isSchemaNode() && !parent.getOptions().isStruct()) 151f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 152f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!parent.isImplicit()) 153f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 154f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Named children only allowed for schemas and structs", 155f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXPATH); 156f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 157f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (parent.getOptions().isArray()) 158f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 159f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Named children not allowed for arrays", 160f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXPATH); 161f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 162f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (createNodes) 163f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 164f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.getOptions().setStruct(true); 165f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 166f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 167f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 168f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode childNode = parent.findChildByName(childName); 169f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 170f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (childNode == null && createNodes) 171f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 172f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions options = new PropertyOptions(); 173f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling childNode = new XMPNode(childName, options); 174f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling childNode.setImplicit(true); 175f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.addChild(childNode); 176f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 177f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 178f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling assert childNode != null || !createNodes; 179f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 180f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return childNode; 181f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 182f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 183f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 184f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 185f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Follow an expanded path expression to find or create a node. 186f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 187f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param xmpTree the node to begin the search. 188f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param xpath the complete xpath 189f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes flag if nodes shall be created 190f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * (when called by <code>setProperty()</code>) 191f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param leafOptions the options for the created leaf nodes (only when 192f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <code>createNodes == true</code>). 193f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the node if found or created or <code>null</code>. 194f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException An exception is only thrown if an error occurred, 195f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * not if a node was not found. 196f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 197f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static XMPNode findNode(XMPNode xmpTree, XMPPath xpath, boolean createNodes, 198f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions leafOptions) throws XMPException 199f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 200f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // check if xpath is set. 201f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (xpath == null || xpath.size() == 0) 202f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 203f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Empty XMPPath", XMPError.BADXPATH); 204f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 205f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 206f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Root of implicitly created subtree to possible delete it later. 207f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Valid only if leaf is new. 208f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode rootImplicitNode = null; 209f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currNode = null; 210f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 211f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // resolve schema step 212f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode = findSchemaNode(xmpTree, 213f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xpath.getSegment(XMPPath.STEP_SCHEMA).getName(), createNodes); 214f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (currNode == null) 215f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 216f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return null; 217f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 218f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (currNode.isImplicit()) 219f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 220f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.setImplicit(false); // Clear the implicit node bit. 221f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling rootImplicitNode = currNode; // Save the top most implicit node. 222f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 223f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 224f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 225f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Now follow the remaining steps of the original XMPPath. 226f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling try 227f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 228f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int i = 1; i < xpath.size(); i++) 229f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 230f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode = followXPathStep(currNode, xpath.getSegment(i), createNodes); 231f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (currNode == null) 232f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 233f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (createNodes) 234f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 235f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // delete implicitly created nodes 236f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling deleteNode(rootImplicitNode); 237f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 238f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return null; 239f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 240f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (currNode.isImplicit()) 241f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 242f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // clear the implicit node flag 243f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.setImplicit(false); 244f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 245f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // if node is an ALIAS (can be only in root step, auto-create array 246f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // when the path has been resolved from a not simple alias type 247f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (i == 1 && 248f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xpath.getSegment(i).isAlias() && 249f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xpath.getSegment(i).getAliasForm() != 0) 250f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 251f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.getOptions().setOption(xpath.getSegment(i).getAliasForm(), true); 252f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 253f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // "CheckImplicitStruct" in C++ 254f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (i < xpath.size() - 1 && 255f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xpath.getSegment(i).getKind() == XMPPath.STRUCT_FIELD_STEP && 256f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling !currNode.getOptions().isCompositeProperty()) 257f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 258f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.getOptions().setStruct(true); 259f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 260f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 261f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (rootImplicitNode == null) 262f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 263f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling rootImplicitNode = currNode; // Save the top most implicit node. 264f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 265f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 266f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 267f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 268f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling catch (XMPException e) 269f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 270f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // if new notes have been created prior to the error, delete them 271f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (rootImplicitNode != null) 272f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 273f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling deleteNode(rootImplicitNode); 274f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 275f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw e; 276f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 277f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 278f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 279f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (rootImplicitNode != null) 280f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 281f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // set options only if a node has been successful created 282f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.getOptions().mergeWith(leafOptions); 283f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currNode.setOptions(currNode.getOptions()); 284f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 285f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 286f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return currNode; 287f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 288f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 289f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 290f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 291f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Deletes the the given node and its children from its parent. 292f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Takes care about adjusting the flags. 293f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param node the top-most node to delete. 294f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 295f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static void deleteNode(XMPNode node) 296f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 297f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode parent = node.getParent(); 298f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 299f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (node.getOptions().isQualifier()) 300f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 301f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // root is qualifier 302f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.removeQualifier(node); 303f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 304f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 305f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 306f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // root is NO qualifier 307f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.removeChild(node); 308f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 309f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 310f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // delete empty Schema nodes 311f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!parent.hasChildren() && parent.getOptions().isSchemaNode()) 312f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 313f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.getParent().removeChild(parent); 314f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 315f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 316f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 317f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 318f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 319f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * This is setting the value of a leaf node. 320f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 321f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param node an XMPNode 322f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param value a value 323f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 324f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static void setNodeValue(XMPNode node, Object value) 325f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 326f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String strValue = serializeNodeValue(value); 327f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!(node.getOptions().isQualifier() && XML_LANG.equals(node.getName()))) 328f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 329f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling node.setValue(strValue); 330f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 331f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 332f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 333f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling node.setValue(Utils.normalizeLangValue(strValue)); 334f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 335f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 336f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 337f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 338f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 339f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Verifies the PropertyOptions for consistancy and updates them as needed. 340f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * If options are <code>null</code> they are created with default values. 341f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 342f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param options the <code>PropertyOptions</code> 343f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param itemValue the node value to set 344f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the updated options. 345f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException If the options are not consistant. 346f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 347f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static PropertyOptions verifySetOptions(PropertyOptions options, Object itemValue) 348f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 349f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 350f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // create empty and fix existing options 351f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (options == null) 352f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 353f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // set default options 354f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling options = new PropertyOptions(); 355f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 356f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 357f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (options.isArrayAltText()) 358f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 359f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling options.setArrayAlternate(true); 360f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 361f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 362f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (options.isArrayAlternate()) 363f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 364f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling options.setArrayOrdered(true); 365f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 366f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 367f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (options.isArrayOrdered()) 368f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 369f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling options.setArray(true); 370f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 371f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 372f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (options.isCompositeProperty() && itemValue != null && itemValue.toString().length() > 0) 373f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 374f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Structs and arrays can't have values", 375f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADOPTIONS); 376f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 377f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 378f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling options.assertConsistency(options.getOptions()); 379f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 380f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return options; 381f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 382f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 383f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 384f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 385f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Converts the node value to String, apply special conversions for defined 386f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * types in XMP. 387f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 388f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param value 389f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the node value to set 390f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the String representation of the node value. 391f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 392f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static String serializeNodeValue(Object value) 393f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 394f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String strValue; 395f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (value == null) 396f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 397f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = null; 398f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 399f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof Boolean) 400f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 401f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromBoolean(((Boolean) value).booleanValue()); 402f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 403f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof Integer) 404f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 405f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromInteger(((Integer) value).intValue()); 406f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 407f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof Long) 408f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 409f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromLong(((Long) value).longValue()); 410f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 411f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof Double) 412f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 413f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromDouble(((Double) value).doubleValue()); 414f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 415f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof XMPDateTime) 416f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 417f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromDate((XMPDateTime) value); 418f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 419f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof GregorianCalendar) 420f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 421f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPDateTime dt = XMPDateTimeFactory.createFromCalendar((GregorianCalendar) value); 422f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.convertFromDate(dt); 423f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 424f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value instanceof byte[]) 425f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 426f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = XMPUtils.encodeBase64((byte[]) value); 427f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 428f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 429f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 430f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling strValue = value.toString(); 431f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 432f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 433f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return strValue != null ? Utils.removeControlChars(strValue) : null; 434f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 435f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 436f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 437f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 438f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * After processing by ExpandXPath, a step can be of these forms: 439f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ul> 440f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>qualName - A top level property or struct field. 441f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>[index] - An element of an array. 442f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>[last()] - The last element of an array. 443f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>[qualName="value"] - An element in an array of structs, chosen by a field value. 444f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>[?qualName="value"] - An element in an array, chosen by a qualifier value. 445f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>?qualName - A general qualifier. 446f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ul> 447f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Find the appropriate child node, resolving aliases, and optionally creating nodes. 448f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 449f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param parentNode the node to start to start from 450f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param nextStep the xpath segment 451f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes 452f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return returns the found or created XMPPath node 453f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 454f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 455f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static XMPNode followXPathStep( 456f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode parentNode, 457f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPPathSegment nextStep, 458f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean createNodes) throws XMPException 459f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 460f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode nextNode = null; 461f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int index = 0; 462f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int stepKind = nextStep.getKind(); 463f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 464f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (stepKind == XMPPath.STRUCT_FIELD_STEP) 465f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 466f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling nextNode = findChildNode(parentNode, nextStep.getName(), createNodes); 467f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 468f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (stepKind == XMPPath.QUALIFIER_STEP) 469f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 470f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling nextNode = findQualifierNode( 471f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parentNode, nextStep.getName().substring(1), createNodes); 472f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 473f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 474f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 475f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // This is an array indexing step. First get the index, then get the node. 476f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 477f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!parentNode.getOptions().isArray()) 478f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 479f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Indexing applied to non-array", XMPError.BADXPATH); 480f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 481f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 482f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (stepKind == XMPPath.ARRAY_INDEX_STEP) 483f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 484f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling index = findIndexedItem(parentNode, nextStep.getName(), createNodes); 485f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 486f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (stepKind == XMPPath.ARRAY_LAST_STEP) 487f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 488f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling index = parentNode.getChildrenLength(); 489f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 490f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (stepKind == XMPPath.FIELD_SELECTOR_STEP) 491f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 492f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String[] result = Utils.splitNameAndValue(nextStep.getName()); 493f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String fieldName = result[0]; 494f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String fieldValue = result[1]; 495f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling index = lookupFieldSelector(parentNode, fieldName, fieldValue); 496f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 497f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (stepKind == XMPPath.QUAL_SELECTOR_STEP) 498f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 499f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String[] result = Utils.splitNameAndValue(nextStep.getName()); 500f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String qualName = result[0]; 501f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String qualValue = result[1]; 502f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling index = lookupQualSelector( 503f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parentNode, qualName, qualValue, nextStep.getAliasForm()); 504f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 505f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 506f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 507f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Unknown array indexing step in FollowXPathStep", 508f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.INTERNALFAILURE); 509f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 510f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 511f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (1 <= index && index <= parentNode.getChildrenLength()) 512f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 513f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling nextNode = parentNode.getChild(index); 514f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 515f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 516f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 517f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return nextNode; 518f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 519f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 520f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 521f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 522f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Find or create a qualifier node under a given parent node. Returns a pointer to the 523f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * qualifier node, and optionally an iterator for the node's position in 524f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the parent's vector of qualifiers. The iterator is unchanged if no qualifier node (null) 525f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * is returned. 526f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> On entry, the qualName parameter must not have the leading '?' from the 527f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * XMPPath step. 528f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 529f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param parent the parent XMPNode 530f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param qualName the qualifier name 531f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes flag if nodes shall be created 532f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the qualifier node if found or created, <code>null</code> otherwise. 533f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 534f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 535f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static XMPNode findQualifierNode(XMPNode parent, String qualName, boolean createNodes) 536f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 537f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 538f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling assert !qualName.startsWith("?"); 539f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 540f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode qualNode = parent.findQualifierByName(qualName); 541f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 542f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (qualNode == null && createNodes) 543f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 544f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling qualNode = new XMPNode(qualName, null); 545f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling qualNode.setImplicit(true); 546f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 547f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling parent.addQualifier(qualNode); 548f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 549f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 550f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return qualNode; 551f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 552f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 553f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 554f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 555f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode an array node 556f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param segment the segment containing the array index 557f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param createNodes flag if new nodes are allowed to be created. 558f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the index or index = -1 if not found 559f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Throws Exceptions 560f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 561f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static int findIndexedItem(XMPNode arrayNode, String segment, boolean createNodes) 562f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 563f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 564f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int index = 0; 565f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 566f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling try 567f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 568f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling segment = segment.substring(1, segment.length() - 1); 569f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling index = Integer.parseInt(segment); 570f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (index < 1) 571f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 572f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Array index must be larger than zero", 573f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXPATH); 574f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 575f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 576f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling catch (NumberFormatException e) 577f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 578f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Array index not digits.", XMPError.BADXPATH); 579f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 580f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 581f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (createNodes && index == arrayNode.getChildrenLength() + 1) 582f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 583f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Append a new last + 1 node. 584f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, null); 585f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling newItem.setImplicit(true); 586f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.addChild(newItem); 587f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 588f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 589f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return index; 590f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 591f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 592f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 593f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 594f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Searches for a field selector in a node: 595f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * [fieldName="value] - an element in an array of structs, chosen by a field value. 596f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * No implicit nodes are created by field selectors. 597f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 598f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode 599f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param fieldName 600f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param fieldValue 601f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the index of the field if found, otherwise -1. 602f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 603f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 604f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static int lookupFieldSelector(XMPNode arrayNode, String fieldName, String fieldValue) 605f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 606f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 607f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int result = -1; 608f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 609f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int index = 1; index <= arrayNode.getChildrenLength() && result < 0; index++) 610f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 611f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currItem = arrayNode.getChild(index); 612f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 613f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!currItem.getOptions().isStruct()) 614f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 615f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Field selector must be used on array of struct", 616f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXPATH); 617f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 618f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 619f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int f = 1; f <= currItem.getChildrenLength(); f++) 620f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 621f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currField = currItem.getChild(f); 622f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!fieldName.equals(currField.getName())) 623f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 624f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling continue; 625f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 626f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (fieldValue.equals(currField.getValue())) 627f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 628f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling result = index; 629f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling break; 630f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 631f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 632f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 633f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 634f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return result; 635f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 636f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 637f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 638f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 639f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Searches for a qualifier selector in a node: 640f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * [?qualName="value"] - an element in an array, chosen by a qualifier value. 641f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * No implicit nodes are created for qualifier selectors, 642f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * except for an alias to an x-default item. 643f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 644f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode an array node 645f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param qualName the qualifier name 646f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param qualValue the qualifier value 647f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param aliasForm in case the qual selector results from an alias, 648f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * an x-default node is created if there has not been one. 649f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the index of th 650f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 651f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 652f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static int lookupQualSelector(XMPNode arrayNode, String qualName, 653f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String qualValue, int aliasForm) throws XMPException 654f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 655f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (XML_LANG.equals(qualName)) 656f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 657f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling qualValue = Utils.normalizeLangValue(qualValue); 658f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int index = XMPNodeUtils.lookupLanguageItem(arrayNode, qualValue); 659f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (index < 0 && (aliasForm & AliasOptions.PROP_ARRAY_ALT_TEXT) > 0) 660f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 661f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode langNode = new XMPNode(ARRAY_ITEM_NAME, null); 662f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode xdefault = new XMPNode(XML_LANG, X_DEFAULT, null); 663f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling langNode.addQualifier(xdefault); 664f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.addChild(1, langNode); 665f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return 1; 666f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 667f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 668f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 669f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return index; 670f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 671f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 672f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 673f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 674f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int index = 1; index < arrayNode.getChildrenLength(); index++) 675f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 676f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currItem = arrayNode.getChild(index); 677f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 678f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = currItem.iterateQualifier(); it.hasNext();) 679f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 680f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode qualifier = (XMPNode) it.next(); 681f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (qualName.equals(qualifier.getName()) && 682f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling qualValue.equals(qualifier.getValue())) 683f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 684f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return index; 685f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 686f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 687f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 688f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return -1; 689f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 690f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 691f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 692f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 693f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 694f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Make sure the x-default item is first. Touch up "single value" 695f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * arrays that have a default plus one real language. This case should have 696f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the same value for both items. Older Adobe apps were hardwired to only 697f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * use the "x-default" item, so we copy that value to the other 698f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * item. 699f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 700f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode 701f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * an alt text array node 702f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 703f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static void normalizeLangArray(XMPNode arrayNode) 704f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 705f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!arrayNode.getOptions().isArrayAltText()) 706f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 707f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 708f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 709f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 710f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // check if node with x-default qual is first place 711f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int i = 2; i <= arrayNode.getChildrenLength(); i++) 712f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 713f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode child = arrayNode.getChild(i); 714f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (child.hasQualifier() && X_DEFAULT.equals(child.getQualifier(1).getValue())) 715f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 716f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // move node to first place 717f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling try 718f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 719f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.removeChild(i); 720f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.addChild(1, child); 721f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 722f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling catch (XMPException e) 723f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 724f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // cannot occur, because same child is removed before 725f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling assert false; 726f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 727f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 728f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (i == 2) 729f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 730f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.getChild(2).setValue(child.getValue()); 731f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 732f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling break; 733f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 734f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 735f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 736f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 737f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 738f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 739f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * See if an array is an alt-text array. If so, make sure the x-default item 740f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * is first. 741f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 742f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode 743f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the array node to check if its an alt-text array 744f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 745f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static void detectAltText(XMPNode arrayNode) 746f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 747f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayNode.getOptions().isArrayAlternate() && arrayNode.hasChildren()) 748f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 749f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean isAltText = false; 750f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = arrayNode.iterateChildren(); it.hasNext();) 751f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 752f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode child = (XMPNode) it.next(); 753f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (child.getOptions().getHasLanguage()) 754f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 755f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling isAltText = true; 756f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling break; 757f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 758f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 759f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 760f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (isAltText) 761f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 762f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.getOptions().setArrayAltText(true); 763f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling normalizeLangArray(arrayNode); 764f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 765f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 766f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 767f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 768f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 769f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 770f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Appends a language item to an alt text array. 771f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 772f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode the language array 773f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param itemLang the language of the item 774f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param itemValue the content of the item 775f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if a duplicate property is added 776f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 777f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static void appendLangItem(XMPNode arrayNode, String itemLang, String itemValue) 778f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 779f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 780f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, itemValue, null); 781f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode langQual = new XMPNode(XML_LANG, itemLang, null); 782f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling newItem.addQualifier(langQual); 783f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 784f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!X_DEFAULT.equals(langQual.getValue())) 785f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 786f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.addChild(newItem); 787f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 788f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 789f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 790f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.addChild(1, newItem); 791f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 792f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 793f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 794f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 795f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 796f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ol> 797f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>Look for an exact match with the specific language. 798f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>If a generic language is given, look for partial matches. 799f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>Look for an "x-default"-item. 800f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>Choose the first item. 801f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ol> 802f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 803f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode 804f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the alt text array node 805f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param genericLang 806f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the generic language 807f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param specificLang 808f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the specific language 809f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the kind of match as an Integer and the found node in an 810f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * array. 811f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 812f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 813f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 814f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static Object[] chooseLocalizedText(XMPNode arrayNode, String genericLang, String specificLang) 815f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 816f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 817f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // See if the array has the right form. Allow empty alt arrays, 818f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // that is what parsing returns. 819f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!arrayNode.getOptions().isArrayAltText()) 820f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 821f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Localized text array is not alt-text", XMPError.BADXPATH); 822f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 823f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (!arrayNode.hasChildren()) 824f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 825f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_NO_VALUES), null }; 826f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 827f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 828f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int foundGenericMatches = 0; 829f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode resultNode = null; 830f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode xDefault = null; 831f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 832f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Look for the first partial match with the generic language. 833f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = arrayNode.iterateChildren(); it.hasNext();) 834f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 835f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currItem = (XMPNode) it.next(); 836f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 837f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // perform some checks on the current item 838f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (currItem.getOptions().isCompositeProperty()) 839f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 840f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Alt-text array item is not simple", XMPError.BADXPATH); 841f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 842f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (!currItem.hasQualifier() 843f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling || !XML_LANG.equals(currItem.getQualifier(1).getName())) 844f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 845f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Alt-text array item has no language qualifier", 846f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXPATH); 847f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 848f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 849f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String currLang = currItem.getQualifier(1).getValue(); 850f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 851f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Look for an exact match with the specific language. 852f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (specificLang.equals(currLang)) 853f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 854f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_SPECIFIC_MATCH), currItem }; 855f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 856f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (genericLang != null && currLang.startsWith(genericLang)) 857f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 858f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (resultNode == null) 859f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 860f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling resultNode = currItem; 861f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 862f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // ! Don't return/break, need to look for other matches. 863f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling foundGenericMatches++; 864f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 865f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (X_DEFAULT.equals(currLang)) 866f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 867f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xDefault = currItem; 868f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 869f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 870f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 871f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // evaluate loop 872f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (foundGenericMatches == 1) 873f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 874f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_SINGLE_GENERIC), resultNode }; 875f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 876f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (foundGenericMatches > 1) 877f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 878f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_MULTIPLE_GENERIC), resultNode }; 879f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 880f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (xDefault != null) 881f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 882f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_XDEFAULT), xDefault }; 883f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 884f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 885f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 886f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Everything failed, choose the first item. 887f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return new Object[] { new Integer(XMPNodeUtils.CLT_FIRST_ITEM), arrayNode.getChild(1) }; 888f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 889f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 890f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 891f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 892f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 893f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Looks for the appropriate language item in a text alternative array.item 894f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 895f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode 896f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * an array node 897f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param language 898f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the requested language 899f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the index if the language has been found, -1 otherwise. 900f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException 901f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 902f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static int lookupLanguageItem(XMPNode arrayNode, String language) throws XMPException 903f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 904f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!arrayNode.getOptions().isArray()) 905f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 906f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Language item must be used on array", XMPError.BADXPATH); 907f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 908f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 909f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int index = 1; index <= arrayNode.getChildrenLength(); index++) 910f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 911f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode child = arrayNode.getChild(index); 912f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!child.hasQualifier() || !XML_LANG.equals(child.getQualifier(1).getName())) 913f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 914f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling continue; 915f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 916f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (language.equals(child.getQualifier(1).getValue())) 917f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 918f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return index; 919f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 920f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 921f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 922f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return -1; 923f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 924f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling} 925