/*
* Copyright 2004-2012 the Seasar Foundation and the Others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.seasar.mayaa.impl.engine.specification.xpath;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jaxen.Context;
import org.jaxen.ContextSupport;
import org.jaxen.JaxenException;
import org.jaxen.NamespaceContext;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.SimpleVariableContext;
import org.jaxen.XPath;
import org.jaxen.XPathFunctionContext;
import org.jaxen.pattern.Pattern;
import org.jaxen.pattern.PatternParser;
import org.jaxen.saxpath.SAXPathException;
import org.seasar.mayaa.engine.specification.Namespace;
import org.seasar.mayaa.engine.specification.Specification;
import org.seasar.mayaa.engine.specification.SpecificationNode;
import org.seasar.mayaa.impl.engine.EngineUtil;
import org.seasar.mayaa.impl.engine.specification.SpecificationUtil;
import org.seasar.mayaa.impl.util.StringUtil;
import org.seasar.mayaa.impl.util.collection.NullIterator;
/**
* @author Masataka Kurihara (Gluegent, Inc.)
*/
public class XPathUtil {
private static final Log LOG = LogFactory.getLog(XPathUtil.class);
private XPathUtil() {
// no instantiation.
}
public static boolean matches(SpecificationNode test,
String xpathExpr, Namespace namespace) {
if (StringUtil.isEmpty(xpathExpr)) {
throw new IllegalArgumentException();
}
NamespaceContext nsContext;
if (namespace == null) {
nsContext = new SimpleNamespaceContext();
} else {
nsContext = new NamespaceContextImpl(namespace);
}
ContextSupport support = new ContextSupport(
nsContext,
XPathFunctionContext.getInstance(),
new SimpleVariableContext(),
SpecificationNavigator.getInstance());
Context context = new Context(support);
try {
Pattern pattern = PatternParser.parse(xpathExpr);
return pattern.matches(test, context);
} catch (JaxenException e) {
throw new RuntimeException(e);
} catch (SAXPathException e) {
throw new RuntimeException(e);
}
}
public static Iterator selectChildNodes(SpecificationNode node,
String xpathExpr, Namespace namespaceable, boolean cascade) {
Specification specification = SpecificationUtil.findSpecification(node);
if (specification == null) {
LOG.warn("node top is not specification." + node.toString());
return NullIterator.getInstance();
}
if (StringUtil.isEmpty(xpathExpr)) {
throw new IllegalArgumentException();
}
if (cascade) {
return new CascadeSelectNodesIterator(
specification, xpathExpr, namespaceable);
}
try {
XPath xpath =
SpecificationXPath.createXPath(xpathExpr, namespaceable);
return xpath.selectNodes(specification).iterator();
} catch (JaxenException e) {
throw new RuntimeException(e);
}
}
// support class ------------------------------------------------
public static class CascadeSelectNodesIterator
implements Iterator {
private Specification _specification;
private String _xpathExpr;
private Namespace _namespaceable;
private Iterator _iterator;
public CascadeSelectNodesIterator(Specification specification,
String xpathExpr, Namespace namespaceable) {
if (specification == null || StringUtil.isEmpty(xpathExpr)) {
throw new IllegalArgumentException();
}
_specification = specification;
_xpathExpr = xpathExpr;
_namespaceable = namespaceable;
}
public boolean hasNext() {
while (true) {
if (_iterator == null) {
XPath xpath = SpecificationXPath.createXPath(
_xpathExpr, _namespaceable);
try {
_iterator = xpath.selectNodes(_specification).iterator();
} catch (JaxenException e) {
throw new RuntimeException(e);
}
}
if (_iterator.hasNext()) {
return true;
}
Specification parent =
EngineUtil.getParentSpecification(_specification);
if (parent == null) {
return false;
}
_specification = parent;
_iterator = null;
}
}
public Object next() {
if (hasNext()) {
return _iterator.next();
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}