blob: 4c07448587a1142cf3e07f32114efdcd595e013a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Hisashi MIYASHITA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.ai.query.impl;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.actf.model.dom.dombycom.IDocumentEx;
import org.eclipse.actf.util.xpath.XPathService;
import org.eclipse.actf.util.xpath.XPathServiceFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLQueryImpl {
private static final String XML_QUERY_NS = "http://www.ibm.com/xmlns/prod/aiBrowser/fennec/xml-query";
private static final XPathService xpathService = XPathServiceFactory.newService();
private final String[] ids;
private Object compiledXPath;
private XMLQueryImpl(String[] ids, Object compiledXPath) {
this.ids = ids;
this.compiledXPath = compiledXPath;
}
public boolean hasTarget() {
return (ids != null) || (compiledXPath != null);
}
public List<Node> query(Node base) {
List<Node> result = null;
if (ids != null) {
if (result == null) {
result = new ArrayList<Node>();
}
Document doc = base.getOwnerDocument();
for (int i = 0; i < ids.length; i++) {
if (doc instanceof IDocumentEx) {
List<Node> r = ((IDocumentEx) doc).getElementsByIdInAllFrames(ids[i]);
result.addAll(r);
} else {
Node n = doc.getElementById(ids[i]);
if (n != null) result.add(n);
}
}
}
if (compiledXPath != null) {
NodeList nl = xpathService.evalForNodeList(compiledXPath, base);
if (nl != null) {
int len = nl.getLength();
if (len > 0) {
if (result == null) {
result = new ArrayList<Node>(len);
}
for (int i = 0; i < len; i++) {
result.add(nl.item(i));
}
}
}
}
return result;
}
static XMLQueryImpl parse(Element e, XMLQueryImpl parentQuery) {
String[] ids = null;
String idrefs = e.getAttributeNS(XML_QUERY_NS, "idrefs");
if (idrefs.length() > 0) {
ids = idrefs.split("[ \r\n\t]");
}
String path = e.getAttributeNS(XML_QUERY_NS, "path");
Object compiled = null;
if (path.length() > 0) {
compiled = xpathService.compile(path);
}
return new XMLQueryImpl(ids, compiled);
}
// --------------------------------------------------------------------------------
// XPath Query Service
// --------------------------------------------------------------------------------
static XMLQueryImpl parseXPath(String xpath) {
Object compiled = xpathService.compile(xpath);
return new XMLQueryImpl(null, compiled);
}
// --------------------------------------------------------------------------------
// Query Serialization
// --------------------------------------------------------------------------------
static Attr serializeQuery(Node domNode, Node usrNode) {
Document doc = usrNode.getOwnerDocument();
String id = getID(domNode);
if (id != null && id.length() > 0) {
Attr attr = doc.createAttributeNS(XML_QUERY_NS, "loc:idrefs");
attr.setNodeValue(id);
return attr;
}
String path = getXPath(domNode);
if (path != null && path.length() > 0) {
Attr attr = doc.createAttributeNS(XML_QUERY_NS, "loc:path");
attr.setNodeValue(path);
return attr;
}
return null;
}
private static String getID(Node node) {
if (!(node instanceof Element))
return null;
Element e = (Element) node;
return e.getAttribute("id");
}
private static String checkID(Node n) {
if (!(n instanceof Element)) return null;
Element e = (Element) n;
String id = e.getAttribute("id");
if (id == null) return null;
Document doc = e.getOwnerDocument();
Node e2 = doc.getElementById(id);
if (!e.isSameNode(e2)) return null;
// ':' is not allowed according to XML spec.
if (id.indexOf(':') >= 0) return null;
return id;
}
private static String getXPath(Node node) {
// return XPathCreator.childPathSequence(n);
StringBuffer ret = new StringBuffer();
for (Node n = node; n != null; n = n.getParentNode()) {
// /* /HTML[1]/ -> ./ */
// if (node.getParentNode() instanceof Document) {
// ret.insert(0, '.');
// break;
// }
if (n instanceof Document) {
break;
}
String id = checkID(n);
// if (id != null) System.err.println("ID " + id + " is used");
if (id != null) {
ret.insert(0, "\")");
ret.insert(0, id);
ret.insert(0, "id(\"");
break;
}
String name = n.getNodeName();
int k = 1;
if (name.startsWith("#")) {
// ITreeItem a = item.getParent();
// Node p = node.getParentNode();
// if (a != null) {
// for (ITreeItem c : a.getChildItems()) {
// if (c == item)
// break;
// Object o = c.getBaseNode();
// if (!(o instanceof Node))
// continue;
// Node n = (Node) o;
// if (n.getParentNode() == p && n.getNodeName().equals(name))
// ++k;
// }
// }
/* currently text() is not supported */
// return calcPath(a); // query the parent node in the nav tree
continue; // query the parent node in the DOM tree
}
else {
Node p = n.getParentNode();
if (p != null) {
for (Node c = p.getFirstChild(); c != null; c = c.getNextSibling()) {
if (c == n)
break;
if (c.getNodeName().equals(name))
++k;
}
}
}
ret.insert(0, ']');
ret.insert(0, k);
ret.insert(0, '[');
ret.insert(0, getNodeNameForXPath(n.getNodeName()));
ret.insert(0, '/');
}
return ret.toString();
}
private static String getNodeNameForXPath(String s) {
if (s.startsWith("#"))
return s.substring(1) + "()";
else
return s;
}
}