package org.openrosa.client.xpath;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
import com.google.gwt.xml.client.Element;
/**
* @author Cosmin
*
* since I don't want to implement a full-blown xpath engine
* our predicate
*/
public class Predicate implements Serializable
{
/**
* Generated serialization ID
*/
private static final long serialVersionUID = -3214921069193850338L;
Vector<Object> resultSet;
Predicate(Vector<Object> inNodeSet, String predicateExpr)
{
int nodeIndex = -1;
if(predicateExpr == null || predicateExpr.length() <= 0) {
resultSet = inNodeSet;
return;
} else //we need to parse predicateExpr
resultSet = new Vector<Object>();
//check if this predicate is just a logical condition or a complete XPath query.
//for now we support only logical conditions
/*If it is a complete XPath expression
{
ResultSet = (new XPathExpression(XML_DOM, XPath Expression))
.getResult();
}//If it is a complete XPath expression */
try {
nodeIndex = Integer.parseInt(predicateExpr);
} catch(NumberFormatException nfe) {
//we do nothing, the predicate was not an index
}
if(nodeIndex != -1) {
resultSet.addElement(inNodeSet.elementAt(nodeIndex));
return;
}
String[] tokens = predicateExpr.split(" and ");
int pos = predicateExpr.indexOf(" and ");
if(pos > 0){
/*Vector resultSet1 = new Vector();
String predicateExpr1 = predicateExpr.substring(0,pos);
fillResultSet(resultSet1, predicateExpr1, inNodeSet);
Vector resultSet2 = new Vector();
String predicateExpr2 = predicateExpr.substring(pos + 5,predicateExpr.length());
fillResultSet(resultSet2, predicateExpr2, inNodeSet);
for(int index = 0; index < resultSet1.size(); index++){
Object obj = resultSet1.get(index);
if(resultSet2.contains(obj))
resultSet.add(obj);
}*/
Vector<Object>[] resultSets = new Vector[tokens.length];
for(int index = 0; index < tokens.length; index++){
resultSets[index] = new Vector<Object>();
fillResultSet(resultSets[index], tokens[index], inNodeSet);
}
Vector<?> resultSet1 = resultSets[0];
for(int index = 0; index < resultSet1.size(); index++){
Object obj = resultSet1.get(index);
boolean allFound = true;
for(int i = 1; i < tokens.length; i++){
Vector<?> curResultSet = resultSets[i];
if(!curResultSet.contains(obj)){
allFound = false;
break;
}
}
if(allFound)
resultSet.add(obj);
}
}
else
fillResultSet(resultSet, predicateExpr, inNodeSet);
//here we should start parsing the predicateExpr
}//constructor
private void fillResultSet(Vector<Object> resultSet, String predicateExpr, Vector<Object> inNodeSet){
String operation = null;
int index = -1;
if((index = predicateExpr.indexOf("=")) != -1) {
operation = "=";
} else if((index = predicateExpr.indexOf("<")) != -1) {
operation = "<";
} else if((index = predicateExpr.indexOf(">")) != -1) {
operation = ">";
} else {
//shouldn't be here
//Added by me on 11/05/2009 to cater for attributes without criteria values. eg [@name]
if(predicateExpr.indexOf("@") != -1){
for(Enumeration<Object> e = inNodeSet.elements(); e.hasMoreElements(); ) {
Object obj = e.nextElement();
String val = ((Element)obj).getAttribute(predicateExpr.substring(1,predicateExpr.length()));
if(val != null && val.trim().length() > 0)
resultSet.addElement(obj);
}
}
return;
}
Member member1 = new Member(new String(predicateExpr.toCharArray(), 0, index));
Member member2 = new Member(new String(predicateExpr.toCharArray(), index+1, predicateExpr.length()-index-1));
for(Enumeration<Object> e = inNodeSet.elements(); e.hasMoreElements(); ) {
Object obj = e.nextElement();
if(operation.equals("="))
if(!member1.eval(obj).equals(member2.eval(obj)))
continue;
else if(operation.equals(">"))
if(member1.eval(obj).compareTo(member2.eval(obj))<0)
continue;
else if(operation.equals("<"))
if(member1.eval(obj).compareTo(member2.eval(obj))>0)
continue;
resultSet.addElement(obj);
}
}
class Member
{
String m = null;
String attribute = null;
Member(String op)
{
this.m = op;
if(op.startsWith("@")) {
attribute = new String(op.toCharArray(), 1, op.length()-1);
}
//for expath expressions enclosed with quotes.
else if( (m.startsWith("'") && m.endsWith("'")) || (m.startsWith("\"") && m.endsWith("\"")) )
m = m.substring(1,m.length()-1);
}
public String eval(Object obj)
{
if(attribute == null)
return m;
if(!(obj instanceof Element))
return "";
Element element = (Element)obj;
String attr = element.getAttribute(attribute);
return attr!=null?attr:"";
}
}
public Vector<Object> getResult()
{
return resultSet;
}//getResult
}