001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.xml.xpath;
018:
019: import java.util.Collections;
020: import java.util.Map;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.springframework.util.Assert;
025: import org.springframework.util.ClassUtils;
026: import org.springframework.xml.JaxpVersion;
027:
028: /**
029: * Factory for compiled <code>XPathExpression</code>s, being aware of JAXP 1.3+ XPath functionality, and Jaxen. Mainly
030: * for internal use of the framework.
031: * <p/>
032: * The goal of this class is to avoid runtime dependencies a specific XPath engine, simply using the best XPath
033: * implementation that is available. Prefers JAXP 1.3+ XPath implementations to Jaxen.
034: *
035: * @author Arjen Poutsma
036: * @see XPathExpression
037: * @since 1.0.0
038: */
039: public abstract class XPathExpressionFactory {
040:
041: private static final Log logger = LogFactory
042: .getLog(XPathExpressionFactory.class);
043:
044: private static final String JAXEN_CLASS_NAME = "org.jaxen.XPath";
045:
046: private static boolean jaxenAvailable;
047:
048: static {
049: // Check whether Jaxen is available
050: try {
051: ClassUtils.forName(JAXEN_CLASS_NAME);
052: jaxenAvailable = true;
053: } catch (ClassNotFoundException ex) {
054: jaxenAvailable = false;
055: }
056: }
057:
058: /**
059: * Create a compiled XPath expression using the given string.
060: *
061: * @param expression the XPath expression
062: * @return the compiled XPath expression
063: * @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
064: * @throws XPathParseException if the given expression cannot be parsed
065: */
066: public static XPathExpression createXPathExpression(
067: String expression) throws IllegalStateException,
068: XPathParseException {
069: return createXPathExpression(expression, Collections.EMPTY_MAP);
070: }
071:
072: /**
073: * Create a compiled XPath expression using the given string and namespaces. The namespace map should consist of
074: * string prefixes mapped to string namespaces.
075: *
076: * @param expression the XPath expression
077: * @param namespaces a map that binds string prefixes to string namespaces
078: * @return the compiled XPath expression
079: * @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
080: * @throws XPathParseException if the given expression cannot be parsed
081: */
082: public static XPathExpression createXPathExpression(
083: String expression, Map namespaces)
084: throws IllegalStateException, XPathParseException {
085: Assert.hasLength(expression, "expression is empty");
086: if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
087: logger.trace("Creating [javax.xml.xpath.XPathExpression]");
088: return Jaxp13XPathExpressionFactory.createXPathExpression(
089: expression, namespaces);
090: } else if (jaxenAvailable) {
091: logger.trace("Creating [org.jaxen.XPath]");
092: return JaxenXPathExpressionFactory.createXPathExpression(
093: expression, namespaces);
094: } else {
095: throw new IllegalStateException(
096: "Could not create XPathExpression: could not locate JAXP 1.3, or Jaxen on the class path");
097: }
098: }
099:
100: }
|