⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmppathparser.java

📁 flash xmp sdk,flash官方SDK
💻 JAVA
字号:
package com.adobe.xmp.impl.xpath;import com.adobe.xmp.XMPError;import com.adobe.xmp.XMPException;import com.adobe.xmp.XMPMetaFactory;import com.adobe.xmp.impl.Utils;import com.adobe.xmp.properties.XMPAliasInfo;/** * Parser for XMP XPaths. * * @since   01.03.2006 */public final class XMPPathParser{	/**	 * Private constructor	 */	private XMPPathParser()	{		// empty	}	/**	 * Split an XMPPath expression apart at the conceptual steps, adding the	 * root namespace prefix to the first property component. The schema URI is	 * put in the first (0th) slot in the expanded XMPPath. Check if the top	 * level component is an alias, but don't resolve it.	 * <p>	 * In the most verbose case steps are separated by '/', and each step can be	 * of these forms:	 * <dl>	 * <dt>prefix:name	 * <dd> A top level property or struct field.	 * <dt>[index]	 * <dd> An element of an array.	 * <dt>[last()]	 * <dd> The last element of an array.	 * <dt>[fieldName=&quot;value&quot;]	 * <dd> An element in an array of structs, chosen by a field value.	 * <dt>[@xml:lang=&quot;value&quot;]	 * <dd> An element in an alt-text array, chosen by the xml:lang qualifier.	 * <dt>[?qualName=&quot;value&quot;]	 * <dd> An element in an array, chosen by a qualifier value.	 * <dt>@xml:lang	 * <dd> An xml:lang qualifier.	 * <dt>?qualName	 * <dd> A general qualifier.	 * </dl>	 * <p>	 * The logic is complicated though by shorthand for arrays, the separating	 * '/' and leading '*' are optional. These are all equivalent: array/*[2]	 * array/[2] array*[2] array[2] All of these are broken into the 2 steps	 * "array" and "[2]".	 * <p>	 * The value portion in the array selector forms is a string quoted by '''	 * or '"'. The value may contain any character including a doubled quoting	 * character. The value may be empty.	 * <p>	 * The syntax isn't checked, but an XML name begins with a letter or '_',	 * and contains letters, digits, '.', '-', '_', and a bunch of special	 * non-ASCII Unicode characters. An XML qualified name is a pair of names	 * separated by a colon.	 * @param schemaNS	 *            schema namespace	 * @param path	 *            property name	 * @return Returns the expandet XMPPath.	 * @throws XMPException	 *             Thrown if the format is not correct somehow.	 * 	 */	public static XMPPath expandXPath(String schemaNS, String path) throws XMPException	{		if (schemaNS == null  ||  path == null)		{			throw new XMPException("Parameter must not be null", XMPError.BADPARAM);		}		XMPPath expandedXPath = new XMPPath();		PathPosition pos = new PathPosition();		pos.path = path;				// Pull out the first component and do some special processing on it: add the schema		// namespace prefix and and see if it is an alias. The start must be a "qualName".		parseRootNode(schemaNS, pos, expandedXPath);		// Now continue to process the rest of the XMPPath string.		while (pos.stepEnd < path.length())		{			pos.stepBegin = pos.stepEnd;						skipPathDelimiter(path, pos);			pos.stepEnd = pos.stepBegin;						XMPPathSegment segment;			if (path.charAt(pos.stepBegin) != '[')			{				// A struct field or qualifier.				segment = parseStructSegment(pos);			}			else			{				// One of the array forms.				segment = parseIndexSegment(pos);			}						if (segment.getKind() == XMPPath.STRUCT_FIELD_STEP)			{				if (segment.getName().charAt(0) == '@')				{					segment.setName("?" + segment.getName().substring(1));					if (!"?xml:lang".equals(segment.getName()))					{						throw new XMPException("Only xml:lang allowed with '@'",								XMPError.BADXPATH);					}				}				if (segment.getName().charAt(0) == '?')				{					pos.nameStart++;					segment.setKind(XMPPath.QUALIFIER_STEP);				}				verifyQualName(pos.path.substring(pos.nameStart, pos.nameEnd));			}			else if (segment.getKind() == XMPPath.FIELD_SELECTOR_STEP)			{				if (segment.getName().charAt(1) == '@')				{					segment.setName("[?" + segment.getName().substring(2));					if (!segment.getName().startsWith("[?xml:lang="))					{						throw new XMPException("Only xml:lang allowed with '@'",								XMPError.BADXPATH);					}				}				if (segment.getName().charAt(1) == '?')				{					pos.nameStart++;					segment.setKind(XMPPath.QUAL_SELECTOR_STEP);					verifyQualName(pos.path.substring(pos.nameStart, pos.nameEnd));				}			}						expandedXPath.add(segment);		}		return expandedXPath;	}	/**	 * @param path	 * @param pos	 * @throws XMPException	 */	private static void skipPathDelimiter(String path, PathPosition pos) throws XMPException	{		if (path.charAt(pos.stepBegin) == '/')		{			// skip slash			pos.stepBegin++;			// added for Java			if (pos.stepBegin >= path.length())			{				throw new XMPException("Empty XMPPath segment", XMPError.BADXPATH);			}		}		if (path.charAt(pos.stepBegin) == '*')		{			// skip asterisk			pos.stepBegin++;			if (pos.stepBegin >= path.length() || path.charAt(pos.stepBegin) != '[')			{				throw new XMPException("Missing '[' after '*'", XMPError.BADXPATH);			}		}	}	/**	 * Parses a struct segment	 * @param pos the current position in the path	 * @return Retusn the segment or an errror	 * @throws XMPException If the sement is empty	 */	private static XMPPathSegment parseStructSegment(PathPosition pos) throws XMPException	{		pos.nameStart = pos.stepBegin;		while (pos.stepEnd < pos.path.length() && "/[*".indexOf(pos.path.charAt(pos.stepEnd)) < 0)		{			pos.stepEnd++;		}		pos.nameEnd = pos.stepEnd;		if (pos.stepEnd == pos.stepBegin)		{			throw new XMPException("Empty XMPPath segment", XMPError.BADXPATH);		}		// ! Touch up later, also changing '@' to '?'.		XMPPathSegment segment = new XMPPathSegment(pos.path.substring(pos.stepBegin, pos.stepEnd),				XMPPath.STRUCT_FIELD_STEP);		return segment;	}	/**	 * Parses an array index segment.	 * 	 * @param pos the xmp path 	 * @return Returns the segment or an error	 * @throws XMPException thrown on xmp path errors	 * 	 */	private static XMPPathSegment parseIndexSegment(PathPosition pos) throws XMPException	{		XMPPathSegment segment;		pos.stepEnd++; // Look at the character after the leading '['.		if ('0' <= pos.path.charAt(pos.stepEnd) && pos.path.charAt(pos.stepEnd) <= '9')		{			// A numeric (decimal integer) array index.			while (pos.stepEnd < pos.path.length() && '0' <= pos.path.charAt(pos.stepEnd)					&& pos.path.charAt(pos.stepEnd) <= '9')			{				pos.stepEnd++;			}			segment = new XMPPathSegment(null, XMPPath.ARRAY_INDEX_STEP);		}		else		{			// Could be "[last()]" or one of the selector forms. Find the ']' or '='.			while (pos.stepEnd < pos.path.length() && pos.path.charAt(pos.stepEnd) != ']'					&& pos.path.charAt(pos.stepEnd) != '=')			{				pos.stepEnd++;			}						if (pos.stepEnd >= pos.path.length())			{				throw new XMPException("Missing ']' or '=' for array index", XMPError.BADXPATH);			}			if (pos.path.charAt(pos.stepEnd) == ']')			{				if (!"[last()".equals(pos.path.substring(pos.stepBegin, pos.stepEnd)))				{					throw new XMPException(						"Invalid non-numeric array index", XMPError.BADXPATH);				}				segment = new XMPPathSegment(null, XMPPath.ARRAY_LAST_STEP);			}			else			{				pos.nameStart = pos.stepBegin + 1;				pos.nameEnd = pos.stepEnd;				pos.stepEnd++; // Absorb the '=', remember the quote.				char quote = pos.path.charAt(pos.stepEnd);				if (quote != '\'' && quote != '"')				{					throw new XMPException(						"Invalid quote in array selector", XMPError.BADXPATH);				}				pos.stepEnd++; // Absorb the leading quote.				while (pos.stepEnd < pos.path.length())				{					if (pos.path.charAt(pos.stepEnd) == quote)					{						// check for escaped quote						if (pos.stepEnd + 1 >= pos.path.length()								|| pos.path.charAt(pos.stepEnd + 1) != quote)						{							break;						}						pos.stepEnd++;					}					pos.stepEnd++;				}				if (pos.stepEnd >= pos.path.length())				{					throw new XMPException("No terminating quote for array selector",							XMPError.BADXPATH);				}				pos.stepEnd++; // Absorb the trailing quote.				// ! Touch up later, also changing '@' to '?'.				segment = new XMPPathSegment(null, XMPPath.FIELD_SELECTOR_STEP);			}		}				if (pos.stepEnd >= pos.path.length() || pos.path.charAt(pos.stepEnd) != ']')		{			throw new XMPException("Missing ']' for array index", XMPError.BADXPATH);		}		pos.stepEnd++;		segment.setName(pos.path.substring(pos.stepBegin, pos.stepEnd));				return segment;	}	/**	 * Parses the root node of an XMP Path, checks if namespace and prefix fit together	 * and resolve the property to the base property if it is an alias. 	 * @param schemaNS the root namespace	 * @param pos the parsing position helper	 * @param expandedXPath  the path to contribute to	 * @throws XMPException If the path is not valid.	 */	private static void parseRootNode(String schemaNS, PathPosition pos, XMPPath expandedXPath)			throws XMPException	{		while (pos.stepEnd < pos.path.length() && "/[*".indexOf(pos.path.charAt(pos.stepEnd)) < 0)		{			pos.stepEnd++;		}		if (pos.stepEnd == pos.stepBegin)		{			throw new XMPException("Empty initial XMPPath step", XMPError.BADXPATH);		}				String rootProp = verifyXPathRoot(schemaNS, pos.path.substring(pos.stepBegin, pos.stepEnd));		XMPAliasInfo aliasInfo = XMPMetaFactory.getSchemaRegistry().findAlias(rootProp);		if (aliasInfo == null)		{			// add schema xpath step			expandedXPath.add(new XMPPathSegment(schemaNS, XMPPath.SCHEMA_NODE));			XMPPathSegment rootStep = new XMPPathSegment(rootProp, XMPPath.STRUCT_FIELD_STEP);			expandedXPath.add(rootStep);		}		else		{			// add schema xpath step and base step of alias			expandedXPath.add(new XMPPathSegment(aliasInfo.getNamespace(), XMPPath.SCHEMA_NODE));			XMPPathSegment rootStep = new XMPPathSegment(verifyXPathRoot(aliasInfo.getNamespace(),					aliasInfo.getPropName()),					XMPPath.STRUCT_FIELD_STEP);			rootStep.setAlias(true);			rootStep.setAliasForm(aliasInfo.getAliasForm().getOptions());			expandedXPath.add(rootStep);						if (aliasInfo.getAliasForm().isArrayAltText())			{				XMPPathSegment qualSelectorStep = new XMPPathSegment("[?xml:lang='x-default']",						XMPPath.QUAL_SELECTOR_STEP);				qualSelectorStep.setAlias(true);				qualSelectorStep.setAliasForm(aliasInfo.getAliasForm().getOptions());				expandedXPath.add(qualSelectorStep);			}			else if (aliasInfo.getAliasForm().isArray())			{				XMPPathSegment indexStep = new XMPPathSegment("[1]",					XMPPath.ARRAY_INDEX_STEP);				indexStep.setAlias(true);				indexStep.setAliasForm(aliasInfo.getAliasForm().getOptions());				expandedXPath.add(indexStep);			}		}	}	/**	 * Verifies whether the qualifier name is not XML conformant or the	 * namespace prefix has not been registered.	 * 	 * @param qualName	 *            a qualifier name	 * @throws XMPException	 *             If the name is not conformant	 */	private static void verifyQualName(String qualName) throws XMPException	{		int colonPos = qualName.indexOf(':');		if (colonPos > 0)		{				String prefix = qualName.substring(0, colonPos);					if (Utils.isXMLNameNS(prefix))			{					String regURI = XMPMetaFactory.getSchemaRegistry().getNamespaceURI(						prefix);				if (regURI != null)				{					return;				}				throw new XMPException("Unknown namespace prefix for qualified name",						XMPError.BADXPATH);			}		}				throw new XMPException("Ill-formed qualified name", XMPError.BADXPATH);	}	/**	 * Verify if an XML name is conformant.	 * 	 * @param name	 *            an XML name	 * @throws XMPException	 *             When the name is not XML conformant	 */	private static void verifySimpleXMLName(String name) throws XMPException	{		if (!Utils.isXMLName(name))		{			throw new XMPException("Bad XML name", XMPError.BADXPATH);		}	}	/**	 * Set up the first 2 components of the expanded XMPPath. Normalizes the various cases of using	 * the full schema URI and/or a qualified root property name. Returns true for normal	 * processing. If allowUnknownSchemaNS is true and the schema namespace is not registered, false	 * is returned. If allowUnknownSchemaNS is false and the schema namespace is not registered, an	 * exception is thrown	 * <P>	 * (Should someday check the full syntax:)	 * 	 * @param schemaNS schema namespace	 * @param rootProp the root xpath segment	 * @return Returns root QName.	 * @throws XMPException Thrown if the format is not correct somehow.	 */	private static String verifyXPathRoot(String schemaNS, String rootProp)		throws XMPException	{		// Do some basic checks on the URI and name. Try to lookup the URI. See if the name is		// qualified.		if (schemaNS == null || schemaNS.length() == 0)		{			throw new XMPException(				"Schema namespace URI is required", XMPError.BADSCHEMA);		}		if ((rootProp.charAt(0) == '?') || (rootProp.charAt(0) == '@'))		{			throw new XMPException("Top level name must not be a qualifier", XMPError.BADXPATH);		}		if (rootProp.indexOf('/') >= 0 || rootProp.indexOf('[') >= 0)		{			throw new XMPException("Top level name must be simple", XMPError.BADXPATH);		}		String prefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(schemaNS);		if (prefix == null)		{			throw new XMPException("Unregistered schema namespace URI", XMPError.BADSCHEMA);		}		// Verify the various URI and prefix combinations. Initialize the		// expanded XMPPath.		int colonPos = rootProp.indexOf(':');		if (colonPos < 0)		{			// The propName is unqualified, use the schemaURI and associated			// prefix.			verifySimpleXMLName(rootProp); // Verify the part before any colon			return prefix + rootProp;		}		else		{			// The propName is qualified. Make sure the prefix is legit. Use the associated URI and			// qualified name.			// Verify the part before any colon			verifySimpleXMLName(rootProp.substring(0, colonPos));			verifySimpleXMLName(rootProp.substring(colonPos));						prefix = rootProp.substring(0, colonPos + 1);			String regPrefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(schemaNS);			if (regPrefix == null)			{				throw new XMPException("Unknown schema namespace prefix", XMPError.BADSCHEMA);			}			if (!prefix.equals(regPrefix))			{				throw new XMPException("Schema namespace URI and prefix mismatch",						XMPError.BADSCHEMA);			}			return rootProp;		}	}}/** * This objects contains all needed char positions to parse. */class PathPosition{	/** the complete path */	public String path = null;	/** the start of a segment name */	int nameStart = 0;	/** the end of a segment name */	int nameEnd = 0;	/** the begin of a step */	int stepBegin = 0;	/** the end of a step */	int stepEnd = 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -