package java_cup.runtime; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class SyntaxTreeXPath { public static List<XMLElement> query(String query, XMLElement element){ if (query.startsWith("/")) query=query.substring(1); return query0(new LinkedList<String>(Arrays.asList( query.split("/"))),0,element,0); } private static List<XMLElement> query0(List<String> q,int idx, XMLElement element,int seq){ if (q.get(idx).isEmpty()) { // match deeper descendant q[1] return matchDeeperDescendant(q,idx+1 ,element,seq); } List<XMLElement> l = new LinkedList<XMLElement>(); if (!match(q.get(idx),element,seq)) return new LinkedList(); if (q.size()-1==idx) return singleton(element); List<XMLElement> children = element.getChildren(); for (int i=0; i< children.size();i++){ XMLElement child= children.get(i); l.addAll(query0(q,idx+1,child,i)); } return l; } private static List<XMLElement> matchDeeperDescendant(List<String> query,int idx, XMLElement element, int seq){ if (query.size()<=idx) return singleton(element); boolean matches = match(query.get(idx),element,seq); List<XMLElement> l = new LinkedList<XMLElement>(); List<XMLElement> children = element.getChildren(); if (matches) return query0(query,idx,element,seq); for (int i=0; i< children.size();i++){ XMLElement child= children.get(i); l.addAll(matchDeeperDescendant(query, idx, child,i)); } return l; } private static boolean match(String m,XMLElement elem,int seq){ // System.out.println("Matching "+elem.tagname+" with "+m); boolean result = true; String[] name = m.split("\\["); String[] tag = name[0].split("\\*"); if (tag[0].isEmpty()) { // start is wildcard if (tag.length>2) result &= elem.tagname.contains(tag[1]); else if (tag.length==2) result &= elem.tagname.endsWith(tag[1]); else result &= false; } else { // match with start if (tag.length==2) result &=elem.tagname.startsWith(tag[1]); else result = elem.tagname.equals(tag[0]); } for (int i=1; i<name.length; i++) { String predicate= name[i]; if (!predicate.endsWith("]")) return false; predicate=predicate.substring(0, predicate.length()-1); if (predicate.startsWith("@")){ if (predicate.substring(1).startsWith("variant")) if ((elem instanceof XMLElement.NonTerminal)&& Integer.parseInt(predicate.substring(9))==((XMLElement.NonTerminal)elem).getVariant()) result&=true; else return false; else return false; } else if (predicate.matches("\\d+")){ result &= Integer.parseInt(predicate)==seq; } else return false; // submatch } return result; } private static List<XMLElement> singleton(XMLElement elem){ LinkedList<XMLElement> l = new LinkedList<XMLElement>(); l.add(elem); return l; } }