package org.openrosa.client.xpath; import java.io.Serializable; import java.util.Vector; import com.google.gwt.xml.client.Node; /** * @author Cosmin * */ public class XPathExpression implements Serializable { /** * Generated serialization ID. */ private static final long serialVersionUID = 2204726896219201531L; String[] locationStepStringsArray; XPathLocationStep[] locationStepArray; Vector resultNodeSet; String expression = null; Node startNode = null; public XPathExpression (Node startNode, String expression){ Vector<String> tmp = new Vector<String>(); this.startNode = startNode; this.expression = expression; //I do not support function name in the start //of an xpath expression //parse if(expression.startsWith("//")) { //this way of handling "//" is obviously incomplete //but we allow it like this because of the lacking resources tmp.addElement("//"); expression = new String(expression.toCharArray(), 2, expression.length()-2); } else if(expression.startsWith("/")) { tmp.addElement("/"); //trace the root element expression = new String(expression.toCharArray(), 1, expression.length()-1); } //System.out.println("Expression "+expression+" start node is "+start); //because there is no support for StringTokenizer //on j2me we remove this /* StringTokenizer st = new StringTokenizer(expression, "/"); locationStepStringsArray = new String[st.countTokens()]; for(int i = 0; i < locationStepStringsArray.length; i++) { locationStepStringsArray[i] = st.nextToken(); System.out.println("location step: "+locationStepStringsArray[i]); } */ for(int start = 0, end = 0; end < expression.length()-1 && end!=-1; start = end+1) { end = expression.indexOf("/", start); if(end != -1){ String token = expression.substring(start,end); if(token.indexOf('@') >= 0 && token.indexOf(']') < 0){ //end = expression.indexOf("/", end + 1); end = expression.indexOf("]", end + 1) + 1; } } //System.out.println("start = "+start+" end = "+end); String s = new String(expression.toCharArray(), start, (end!=-1?end:expression.length())-start); if(s.indexOf('@') > 0) addAttributeSteps(s,tmp); else tmp.addElement(s); } locationStepStringsArray = new String[tmp.size()]; tmp.copyInto(locationStepStringsArray); tmp = null; //the result node set should contain nodes //with regard to the starting poing of the xpath expression //for now just pass the root of the document resultNodeSet = new Vector<Node>(); resultNodeSet.addElement(startNode); boolean attributeFound = false; Vector<Object> prevResults = null; //start processing every location for(int j=0; j < locationStepStringsArray.length; j++) { prevResults = new Vector<Object>(); String locationStepString = locationStepStringsArray[j]; if(locationStepString.indexOf('@') >= 0){ if(attributeFound) prevResults = resultNodeSet; attributeFound = true; } else attributeFound = false; XPathLocationStep locationStep = new XPathLocationStep(locationStepString); resultNodeSet = locationStep.getResult(resultNodeSet, prevResults); } } private void addAttributeSteps(String step, Vector<String> list){ int posBeg = 0; int posEnd = step.indexOf(" and "); /*if(posEnd > 0){ //TODO Need to support more than two and expressions list.addElement(step.substring(posBeg, posEnd+1).trim() + "]"); posBeg = posEnd + 5; posEnd = step.indexOf(']',posBeg); list.addElement(step.substring(0, step.indexOf('@'))+step.substring(posBeg, posEnd+1)); posBeg = posEnd + 1; posEnd = step.indexOf(']',posBeg); } else*/ posEnd = step.indexOf(']',posBeg); while(posEnd > 0){ list.addElement(step.substring(posBeg, posEnd+1)); posBeg = posEnd + 1; if(posBeg >= step.length()) break; posEnd = step.indexOf(']',posBeg); } } public Vector<Node> getResult(){ return resultNodeSet; } }