All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdom2.xpath.util.AbstractXPathCompiled Maven / Gradle / Ivy

Go to download

A complete, Java-based solution for accessing, manipulating, and outputting XML data

There is a newer version: 2.0.2
Show newest version
/*--

 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.

 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows
    these conditions in the documentation and/or other materials
    provided with the distribution.

 3. The name "JDOM" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact .

 4. Products derived from this software may not be called "JDOM", nor
    may "JDOM" appear in their name, without prior written permission
    from the JDOM Project Management .

 In addition, we request (but do not require) that you include in the
 end-user documentation provided with the redistribution and/or in the
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed by the
      JDOM Project (http://www.jdom.org/)."
 Alternatively, the acknowledgment may be graphical using the logos
 available at http://www.jdom.org/images/logos.

 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 This software consists of voluntary contributions made by many
 individuals on behalf of the JDOM Project and was originally
 created by Jason Hunter  and
 Brett McLaughlin .  For more information
 on the JDOM Project, please see .

 */

package org.jdom2.xpath.util;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Namespace;
import org.jdom2.Verifier;
import org.jdom2.filter.Filter;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathDiagnostic;

/**
 * A mostly-implemented XPathExpression that only needs two methods to be
 * implemented in order to satisfy the complete API. Subclasses of this
 * MUST correctly override the clone() method which in turn
 * should call super.clone();
 * 
 * @param 
 *        The generic type of the returned values.
 * @author Rolf Lear
 */
public abstract class AbstractXPathCompiled implements XPathExpression {
	
	private static final class NamespaceComparator implements Comparator {
		@Override
		public int compare(Namespace ns1, Namespace ns2) {
			return ns1.getPrefix().compareTo(ns2.getPrefix());
		}
	}
	
	private static final NamespaceComparator NSSORT = new NamespaceComparator();

	private final Map xnamespaces = new HashMap();
	// Not final to support cloning.
	private Map> xvariables = new HashMap>();
	private final String xquery;
	private final Filter xfilter;

	/**
	 * Construct an XPathExpression.
	 * 
	 * @see XPathExpression for conditions which throw
	 *      {@link NullPointerException} or {@link IllegalArgumentException}.
	 * @param query
	 *        The XPath query
	 * @param filter
	 *        The coercion filter.
	 * @param variables
	 *        A map of variables.
	 * @param namespaces
	 *        The namespaces referenced from the query.
	 */
	public AbstractXPathCompiled(final String query, final Filter filter,
			final Map variables, final Namespace[] namespaces) {
		if (query == null) {
			throw new NullPointerException("Null query");
		}
		if (filter == null) {
			throw new NullPointerException("Null filter");
		}
		xnamespaces.put(Namespace.NO_NAMESPACE.getPrefix(),
				Namespace.NO_NAMESPACE);
		if (namespaces != null) {
			for (Namespace ns : namespaces) {
				if (ns == null) {
					throw new NullPointerException("Null namespace");
				}
				final Namespace oldns = xnamespaces.put(ns.getPrefix(), ns);
				if (oldns != null && oldns != ns) {
					throw new IllegalArgumentException(
							"A Namespace with the prefix '" + ns.getPrefix()
									+ "' has already been declared.");
				}
			}
		}

		if (variables != null) {
			for (Map.Entry me : variables.entrySet()) {
				final String qname = me.getKey();
				if (qname == null) {
					throw new NullPointerException("Variable with a null name");
				}
				final int p = qname.indexOf(':');
				final String pfx = p < 0 ? "" : qname.substring(0, p);
				final String lname = p < 0 ? qname : qname.substring(p + 1);

				final String vpfxmsg = Verifier.checkNamespacePrefix(pfx);
				if (vpfxmsg != null) {
					throw new IllegalArgumentException("Prefix '" + pfx
							+ "' for variable " + qname + " is illegal: "
							+ vpfxmsg);
				}
				final String vnamemsg = Verifier.checkXMLName(lname);
				if (vnamemsg != null) {
					throw new IllegalArgumentException("Variable name '"
							+ lname + "' for variable " + qname
							+ " is illegal: " + vnamemsg);
				}

				final Namespace ns = xnamespaces.get(pfx);
				if (ns == null) {
					throw new IllegalArgumentException("Prefix '" + pfx
							+ "' for variable " + qname
							+ " has not been assigned a Namespace.");
				}

				Map vmap = xvariables.get(ns.getURI());
				if (vmap == null) {
					vmap = new HashMap();
					xvariables.put(ns.getURI(), vmap);
				}

				if (vmap.put(lname, me.getValue()) != null) {
					throw new IllegalArgumentException("Variable with name "
							+ me.getKey() + "' has already been defined.");
				}
			}
		}
		xquery = query;
		xfilter = filter;
	}

	/**
	 * Subclasses of this AbstractXPathCompile class must call super.clone() in
	 * their clone methods!
	 * 

* This would be a sample clone method from a subclass: * * *

	 * 		public XPathExpression<T> clone() {
	 * 			{@literal @}SuppressWarnings("unchecked")
	 * 			final MyXPathCompiled<T> ret = (MyXPathCompiled<T>)super.clone();
	 * 			// change any fields that need to be cloned.
	 * 			....
	 * 			return ret;
	 * 		}
	 * 
* * Here's the documentation from {@link XPathExpression#clone()} *

* {@inheritDoc} */ @Override public XPathExpression clone() { AbstractXPathCompiled ret = null; try { @SuppressWarnings("unchecked") final AbstractXPathCompiled c = (AbstractXPathCompiled) super .clone(); ret = c; } catch (CloneNotSupportedException cnse) { throw new IllegalStateException( "Should never be getting a CloneNotSupportedException!", cnse); } Map> vmt = new HashMap>(); for (Map.Entry> me : xvariables.entrySet()) { final Map cmap = new HashMap(); for (Map.Entry ne : me.getValue().entrySet()) { cmap.put(ne.getKey(), ne.getValue()); } vmt.put(me.getKey(), cmap); } ret.xvariables = vmt; return ret; } @Override public final String getExpression() { return xquery; } @Override public final Namespace getNamespace(final String prefix) { final Namespace ns = xnamespaces.get(prefix); if (ns == null) { throw new IllegalArgumentException("Namespace with prefix '" + prefix + "' has not been declared."); } return ns; } @Override public Namespace[] getNamespaces() { final Namespace[] nsa = xnamespaces.values().toArray( new Namespace[xnamespaces.size()]); Arrays.sort(nsa, NSSORT); return nsa; } @Override public final Object getVariable(final String name, Namespace uri) { final Map vmap = xvariables.get(uri == null ? "" : uri.getURI()); if (vmap == null) { throw new IllegalArgumentException("Variable with name '" + name + "' in namespace '" + uri.getURI() + "' has not been declared."); } final Object ret = vmap.get(name); if (ret == null) { if (!vmap.containsKey(name)) { throw new IllegalArgumentException("Variable with name '" + name + "' in namespace '" + uri.getURI() + "' has not been declared."); } // leave translating null variable values to the implementation. return null; } return ret; } @Override public Object getVariable(String qname) { if (qname == null) { throw new NullPointerException( "Cannot get variable value for null qname"); } final int pos = qname.indexOf(':'); if (pos >= 0) { return getVariable(qname.substring(pos + 1), getNamespace(qname.substring(0, pos))); } return getVariable(qname, Namespace.NO_NAMESPACE); } @Override public Object setVariable(String name, Namespace uri, Object value) { final Object ret = getVariable(name, uri); // if that succeeded then we have it easy.... xvariables.get(uri.getURI()).put(name, value); return ret; } @Override public Object setVariable(String qname, Object value) { if (qname == null) { throw new NullPointerException( "Cannot get variable value for null qname"); } final int pos = qname.indexOf(':'); if (pos >= 0) { return setVariable(qname.substring(pos + 1), getNamespace(qname.substring(0, pos)), value); } return setVariable(qname, Namespace.NO_NAMESPACE, value); } @Override public final Filter getFilter() { return xfilter; } @Override public List evaluate(Object context) { return xfilter.filter(evaluateRawAll(context)); } /** * */ @Override public T evaluateFirst(Object context) { Object raw = evaluateRawFirst(context); if (raw == null) { return null; } return xfilter.filter(raw); } @Override public XPathDiagnostic diagnose(Object context, boolean firstonly) { final List result = firstonly ? Collections .singletonList(evaluateRawFirst(context)) : evaluateRawAll(context); return new XPathDiagnosticImpl(context, this, result, firstonly); } @Override public String toString() { int nscnt = xnamespaces.size(); int vcnt = 0; for (Map cmap : xvariables.values()) { vcnt += cmap.size(); } return String.format( "[XPathExpression: %d namespaces and %d variables for query %s]", nscnt, vcnt, getExpression()); } /** * This is the raw expression evaluator to be implemented by the back-end * XPath library. * * @param context * The context against which to evaluate the query * @return A list of XPath results. */ protected abstract List evaluateRawAll(Object context); /** * This is the raw expression evaluator to be implemented by the back-end * XPath library. When this method is processed the implementing library is * free to stop processing when the result that would be the first result is * retrieved. *

* Only the first value in the result will be processed (if any). * * @param context * The context against which to evaluate the query * @return The first item in the XPath results, or null if there are no * results. */ protected abstract Object evaluateRawFirst(Object context); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy