/*
* © Copyright IBM Corp. 2012
*
* 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.
*/
/*
* Created on June 14, 2005
*
*/
package com.ibm.commons.xml.xpath.xml;
import java.util.Iterator;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.ibm.commons.xml.DOMUtil;
import com.ibm.commons.xml.NamespaceContext;
import com.ibm.commons.xml.XMLException;
import com.ibm.commons.xml.XPathContext;
import com.ibm.commons.xml.XResult;
import com.ibm.commons.xml.drivers.XMLParserDriver;
import com.ibm.commons.xml.xpath.AbstractExpression;
import com.ibm.commons.xml.xpath.XPathException;
/**
* @author Mark Wallace
* @author Eugene Konstantinov
*/
public class XmlComplexExpression extends AbstractExpression {
private XMLParserDriver domDriver;
private Object compiledXPath;
/**
* @param expression
*/
public XmlComplexExpression(XMLParserDriver domDriver, String expression, Object compiledXPath) {
super(expression);
this.domDriver = domDriver;
this.compiledXPath = compiledXPath;
}
/* (non-Javadoc)
* @see com.ibm.commons.xml.xpath.XPathExpression#supportsXPathContext()
*/
public boolean supportsXPathContext() {
return true;
}
/* (non-Javadoc)
* @see com.ibm.commons.xml.xpath.XPathExpression#pushXPathContext(java.lang.Object)
*/
public void pushXPathContext(Object node) throws XPathException {
try {
Document document = getDocument(node);
DOMUtil.pushXPathContext(document, getExpression());
}
catch (XMLException xe) {
throw new XPathException(xe);
}
}
/* (non-Javadoc)
* @see com.ibm.commons.xml.xpath.XPathExpression#popXPathContext(java.lang.Object)
*/
public void popXPathContext(Object node) throws XPathException {
try {
Document document = getDocument(node);
XPathContext context = DOMUtil.getXPathContext(document);
if (context != null && context.getExpression().equals(getExpression())) {
DOMUtil.popXPathContext(document);
}
}
catch (XMLException xe) {
throw new XPathException(xe);
}
}
/* (non-Javadoc)
* @see com.ibm.commons.xml.xpath.AbstractExpression#resolveNamespaceContext(java.lang.Object, com.ibm.commons.xml.NamespaceContext)
*/
public NamespaceContext resolveNamespaceContext(Object node, NamespaceContext ns) {
return Utils.resolveNamespaceContext((Node)node, ns);
}
/* (non-Javadoc)
* @see com.ibm.commons.xml.xpath.XPathExpression#isValid(java.lang.Object)
*/
public boolean isValid(Object node) {
return false;
}
public Object valueOf(Object node) {
return node;
}
/* (non-Javadoc)
* @see com.ibm.xfaces.xpath.XPathExpression#isReadOnly(java.lang.Object)
*/
public boolean isReadOnly(Object node) {
return false;
}
/*
* (non-Javadoc)
*
* @see com.ibm.xfaces.xpath.XPathExpression#isSimple()
*/
public boolean isSimple() {
return false;
}
public boolean isFromRoot() {
return getExpression().startsWith("/");
}
/*
* (non-Javadoc)
*
* @see com.ibm.xfaces.xpath.XPathExpression#eval(java.lang.Object)
*/
protected XResult doEval(Object node, NamespaceContext namespaceContext) throws XPathException {
if (node instanceof Document) {
Document document = (Document)node;
XPathContext pathContext = DOMUtil.getXPathContext(document);
if (pathContext != null) {
node = pathContext.getContextNodes();
// create the context nodes if they don't exist
if (node == null) {
try {
pathContext.createNodes();
}
catch (XMLException xe) {
throw new XPathException(xe);
}
node = pathContext.getContextNodes();
}
}
}
if (node == null) {
throw new XPathException(new NullPointerException("Cannot evaluate an XPath on a null object")); // $NLS-XmlComplexExpression.CannotevaluateanXPathonanullobjec-1$
}
// WARN: Xerces is having Node also implementing NodeList
// We first check Node to be sure.
if (node instanceof Node) {
Node nodeObj = (Node)node;
namespaceContext = resolveNamespaceContext(nodeObj,namespaceContext);
return domDriver.evaluateXPath(nodeObj,compiledXPath,namespaceContext);
}
if (node instanceof NodeList) {
NodeList nodeList = (NodeList)node;
namespaceContext = resolveNamespaceContext(nodeList.item(0),namespaceContext);
XResult r = domDriver.evaluateXPath(nodeList,compiledXPath,namespaceContext);
return r;
}
throw new XPathException(null,"Try to evaluate an XPath on a object that is not a node or a node list"); // $NLS-XmlComplexExpression.TrytoevaluateanXPathonaobjectthat-1$
}
/*
* (non-Javadoc)
*
* @see com.ibm.xfaces.xpath.XPathExpression#createNodes(java.lang.Object,
* java.lang.Object)
*/
protected Object doCreateNodes(Object node, NamespaceContext namespaceContext)
throws XPathException {
throw new XPathException(null,"CREATE nodes not supported by complex expressions."); // $NLS-XmlComplexExpression.CREATEnodesnotsupportedbycomplexe-1$
}
/*
* (non-Javadoc)
*
* @see com.ibm.xfaces.xpath.XPathExpression#setValue(java.lang.Object,
* java.lang.Object)
*/
protected void doSetValue(Object node, Object value, NamespaceContext nsContext, boolean autoCreate) throws XPathException {
if (node == null) {
throw new XPathException(new NullPointerException("Cannot set a value on a null object")); // $NLS-XmlComplexExpression.Cannotsetavalueonanullobject-1$
}
if (!(node instanceof Node)) {
throw new XPathException(null,"Try to evaluate to set a value on a object that is not a node"); // $NLS-XmlComplexExpression.Trytoevaluatetosetavalueonaobject-1$
}
Node nodeObj = (Node)node;
nsContext = resolveNamespaceContext(nodeObj,nsContext);
XResult r = domDriver.evaluateXPath(nodeObj,compiledXPath,nsContext);
if(r.isEmpty()) {
throw new XPathException(null,"Cannot create XPath {0}",getExpression()); // $NLS-XmlComplexExpression.CannotcreateXPath0-1$
}
if(r.isValue()) {
throw new XPathException(null,"Cannot set a value on a value result, XPath={0}",getExpression()); // $NLS-XmlComplexExpression.CannotsetavalueonavalueresultXPat-1$
}
String strValue = Utils.getAsString(value);
for( Iterator it=r.getNodeIterator(); it.hasNext(); ) {
Object n = (Object)it.next();
if( n instanceof Node ) {
DOMUtil.setTextValue((Node)n, strValue);
}
}
}
protected Document getDocument(Object node) throws XMLException {
if (node instanceof Document) {
return (Document)node;
}
return ((Node)node).getOwnerDocument();
}
}