/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-06 Wolfgang M. Meier
* meier@ifs.tu-darmstadt.de
* http://exist.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.xquery;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
import org.exist.dom.AVLTreeNodeSet;
import org.exist.dom.DocumentImpl;
import org.exist.dom.NodeProxy;
import org.exist.memtree.DocumentBuilderReceiver;
import org.exist.memtree.MemTreeBuilder;
import org.exist.memtree.NodeImpl;
import org.exist.numbering.NodeId;
import org.exist.storage.DBBroker;
import org.exist.util.serializer.DOMStreamer;
import org.exist.util.serializer.SerializerPool;
import org.exist.xmldb.LocalXMLResource;
import org.exist.xmldb.RemoteXMLResource;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.value.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
public class XPathUtil {
/**
* Convert Java object to an XQuery sequence. Objects of type Sequence are
* directly returned, other objects are converted into the corresponding
* internal types.
*
* @param obj
* @return XQuery sequence
* @throws XPathException
*/
public final static Sequence javaObjectToXPath(Object obj, XQueryContext context)
throws XPathException {
return javaObjectToXPath(obj, context, true);
}
public final static Sequence javaObjectToXPath(Object obj, XQueryContext context,
boolean expandChars) throws XPathException {
if (obj == null)
//return Sequence.EMPTY_SEQUENCE;
return null;
if (obj instanceof Sequence)
return (Sequence) obj;
else if (obj instanceof String) {
StringValue v = new StringValue((String) obj);
return (expandChars ? v.expand() : v);
} else if (obj instanceof Boolean)
return BooleanValue.valueOf(((Boolean) obj).booleanValue());
else if (obj instanceof Float)
return new FloatValue(((Float) obj).floatValue());
else if (obj instanceof Double)
return new DoubleValue(((Double) obj).doubleValue());
else if (obj instanceof Short)
return new IntegerValue(((Short) obj).shortValue(), Type.SHORT);
else if (obj instanceof Integer)
return new IntegerValue(((Integer) obj).intValue(), Type.INT);
else if (obj instanceof Long)
return new IntegerValue(((Long) obj).longValue(), Type.LONG);
else if (obj instanceof byte[])
return new Base64Binary((byte[]) obj);
else if (obj instanceof ResourceSet) {
Sequence seq = new AVLTreeNodeSet();
try {
DBBroker broker = context.getBroker();
for(ResourceIterator it = ((ResourceSet)obj).getIterator(); it.hasMoreResources();) {
seq.add(getNode(broker, (XMLResource)it.nextResource()));
}
} catch (XMLDBException xe) {
throw new XPathException("Failed to convert ResourceSet to node: " + xe.getMessage());
}
return seq;
} else if (obj instanceof XMLResource) {
return getNode(context.getBroker(), (XMLResource)obj);
} else if (obj instanceof Node) {
DOMStreamer streamer = (DOMStreamer) SerializerPool.getInstance().borrowObject(DOMStreamer.class);
try {
MemTreeBuilder builder = new MemTreeBuilder(context);
builder.startDocument();
DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(
builder);
streamer.setContentHandler(receiver);
streamer.serialize((Node) obj, false);
return builder.getDocument().getNode(1);
} catch (SAXException e) {
throw new XPathException(
"Failed to transform node into internal model: "
+ e.getMessage());
} finally {
SerializerPool.getInstance().returnObject(streamer);
}
} else if (obj instanceof List) {
boolean createNodeSequence = true;
Object next;
for (Iterator i = ((List) obj).iterator(); i.hasNext();) {
next = i.next();
if (!(next instanceof NodeProxy))
createNodeSequence = false;
}
Sequence seq = null;
if (createNodeSequence)
seq = new AVLTreeNodeSet();
else
seq = new ValueSequence();
for (Iterator i = ((List) obj).iterator(); i.hasNext();) {
seq.add((Item) javaObjectToXPath(i.next(), context, expandChars));
}
return seq;
} else if (obj instanceof NodeList) {
DOMStreamer streamer = (DOMStreamer) SerializerPool.getInstance().borrowObject(DOMStreamer.class);
try {
MemTreeBuilder builder = new MemTreeBuilder();
builder.startDocument();
DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(
builder);
streamer.setContentHandler(receiver);
ValueSequence seq = new ValueSequence();
NodeList nl = (NodeList) obj;
int last = builder.getDocument().getLastNode();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
streamer.serialize(n, false);
NodeImpl created = builder.getDocument().getNode(last + 1);
seq.add(created);
last = builder.getDocument().getLastNode();
}
return seq;
} catch (SAXException e) {
throw new XPathException(
"Failed to transform node into internal model: "
+ e.getMessage());
} finally {
SerializerPool.getInstance().returnObject(streamer);
}
} else if (obj instanceof Object[]) {
boolean createNodeSequence = true;
Object[] array = (Object[]) obj;
for (int i = 0; i < array.length; i++) {
if (!(array[i] instanceof NodeProxy))
createNodeSequence = false;
}
Sequence seq = null;
if (createNodeSequence)
seq = new AVLTreeNodeSet();
else
seq = new ValueSequence();
for (int i = 0; i < array.length; i++) {
seq.add((Item) javaObjectToXPath(array[i], context, expandChars));
}
return seq;
} else
return new JavaObjectValue(obj);
}
public final static int javaClassToXPath(Class clazz) {
if (clazz == String.class)
return Type.STRING;
else if (clazz == Boolean.class || clazz == boolean.class)
return Type.BOOLEAN;
else if (clazz == Integer.class || clazz == int.class
|| clazz == Long.class || clazz == long.class
|| clazz == Short.class || clazz == short.class
|| clazz == Byte.class || clazz == byte.class)
return Type.INTEGER;
else if (clazz == Double.class || clazz == double.class)
return Type.DOUBLE;
else if (clazz == Float.class || clazz == float.class)
return Type.FLOAT;
else if (clazz.isAssignableFrom(Node.class))
return Type.NODE;
else
return Type.JAVA_OBJECT;
}
/**
* Converts an XMLResource into a NodeProxy.
*
* @param broker The DBBroker to use to access the database
* @param xres The XMLResource to convert
* @return A NodeProxy for accessing the content represented by xres
* @throws XPathException if an XMLDBException is encountered
*/
public static final NodeProxy getNode(DBBroker broker, XMLResource xres) throws XPathException {
if(xres instanceof LocalXMLResource) {
LocalXMLResource lres = (LocalXMLResource)xres;
try {
return lres.getNode();
} catch (XMLDBException xe) {
throw new XPathException("Failed to convert LocalXMLResource to node: " + xe.getMessage());
}
}
DocumentImpl document;
try {
document = broker.getCollection(XmldbURI.xmldbUriFor(xres.getParentCollection().getName())).getDocument(broker, XmldbURI.xmldbUriFor(xres.getDocumentId()));
} catch (URISyntaxException xe) {
throw new XPathException(xe);
} catch (XMLDBException xe) {
throw new XPathException("Failed to get document for RemoteXMLResource: " + xe.getMessage());
}
NodeId nodeId = broker.getBrokerPool().getNodeFactory().createFromString(((RemoteXMLResource)xres).getNodeId());
return new NodeProxy(document, nodeId);
}
}