Package com.envoisolutions.sxc.xpath

Source Code of com.envoisolutions.sxc.xpath.XPathBuilder$ExpressionState

package com.envoisolutions.sxc.xpath;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.jaxen.JaxenHandler;
import org.jaxen.expr.AllNodeStep;
import org.jaxen.expr.EqualityExpr;
import org.jaxen.expr.Expr;
import org.jaxen.expr.FunctionCallExpr;
import org.jaxen.expr.LiteralExpr;
import org.jaxen.expr.LocationPath;
import org.jaxen.expr.LogicalExpr;
import org.jaxen.expr.NameStep;
import org.jaxen.expr.NumberExpr;
import org.jaxen.expr.Predicate;
import org.jaxen.expr.TextNodeStep;
import org.jaxen.expr.XPathExpr;
import org.jaxen.saxpath.Axis;
import org.jaxen.saxpath.SAXPathException;
import org.jaxen.saxpath.helpers.XPathReaderFactory;

import com.envoisolutions.sxc.Context;
import com.envoisolutions.sxc.builder.Builder;
import com.envoisolutions.sxc.builder.CodeBody;
import com.envoisolutions.sxc.builder.ElementParserBuilder;
import com.envoisolutions.sxc.builder.ParserBuilder;
import com.envoisolutions.sxc.builder.impl.BuilderImpl;
import com.envoisolutions.sxc.xpath.impl.XPathEvaluatorImpl;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JPrimitiveType;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;

public class XPathBuilder {
    private Map<String,String> namespaceContext;
    private ElementParserBuilder parserBldr;
   
    private Map<String, XPathEventHandler> eventHandlers = new HashMap<String, XPathEventHandler>();
    private Map<String, Object> vars = new HashMap<String, Object>();
    private JType eventHandlerType;
    private JType stringType;
    private Builder builder;
    private JType eventType;
    private int varCount = 0;
    private JPrimitiveType boolType;
    private JPrimitiveType intType;

    public XPathBuilder() {
        super();
       
        builder = new BuilderImpl();
        parserBldr = builder.getParserBuilder();
       
        eventHandlerType = parserBldr.getCodeModel()._ref(XPathEventHandler.class);
        eventType = parserBldr.getCodeModel()._ref(XPathEvent.class);
        stringType = parserBldr.getCodeModel()._ref(String.class);
        boolType = parserBldr.getCodeModel().BOOLEAN;
        intType = parserBldr.getCodeModel().INT;
    }

    public void listen(String expr, XPathEventHandler handler) {
        eventHandlers.put(expr, handler);
    }
   
    public XPathEvaluator compile() {
        for (Map.Entry<String, XPathEventHandler> e : eventHandlers.entrySet()) {
            compileEventHandler(e.getKey(), e.getValue());
        }
       
        Context context = builder.compile();
        context.putAll(vars);
       
        return new XPathEvaluatorImpl(context);
    }
   
    public void compileEventHandler(String expr, XPathEventHandler eventHandler) {
        String varName = "obj" + vars.size();
        vars.put(varName, eventHandler);
       
        ParserBuilder xpathBuilder = parserBldr;
        try {
            org.jaxen.saxpath.XPathReader reader = XPathReaderFactory.createReader();
           
            JaxenHandler handler = new JaxenHandler();
            reader.setXPathHandler(handler);
            reader.parse(expr);
           
            XPathExpr path = handler.getXPathExpr(true);
           
            Object o = handleExpression(parserBldr, path.getRootExpr());
            if (o instanceof ExpressionState) {
                ExpressionState exp = (ExpressionState) o;
                JVar var = exp.getVar();
                ParserBuilder builder = exp.getBuilder();
                JBlock block = builder.getBody().getBlock();
               
                xpathBuilder = builder.newState(block._if(var)._then());
            } else {
                xpathBuilder = (ParserBuilder) o;
            }
        } catch (SAXPathException e) {
            throw new XPathException(e);
        }
       
        CodeBody body = xpathBuilder.getBody();
       
        // grab the event handler out of the context
        JVar handlerVar = body.decl(eventHandlerType, varName,
                                    JExpr.cast(eventHandlerType,
                                               JExpr._super().ref("context").invoke("get").arg(varName)));

        body.add(handlerVar.invoke("onMatch").arg(JExpr._new(eventType).arg(JExpr.lit(expr)).arg(xpathBuilder.getXSR())));
    }

    private Object handleExpression(ElementParserBuilder xpathBuilder, Expr expr) {
        // System.out.println("Expression " + expr);
        if (expr instanceof LocationPath) {
            return handle(xpathBuilder, (LocationPath) expr);
        } else if (expr instanceof EqualityExpr) {
            return handle(xpathBuilder, (EqualityExpr) expr);
        } else if (expr instanceof LiteralExpr) {
            return handle(xpathBuilder, (LiteralExpr) expr);
        } else if (expr instanceof FunctionCallExpr) {
            return handle(xpathBuilder, (FunctionCallExpr) expr);
        } else if (expr instanceof LogicalExpr) {
            return handle(xpathBuilder, (LogicalExpr) expr);
        } else if (expr instanceof NumberExpr) {
            return handle(xpathBuilder, (NumberExpr) expr);
        } else {
            throw new XPathException("Unknown expression type " + expr);
        }
    }

    private ExpressionState handle(ElementParserBuilder xpathBuilder, LiteralExpr expr) {
        JVar var = xpathBuilder.getBody().decl(stringType,
                                               "_literal" + varCount++,
                                               JExpr.lit(expr.getLiteral()));
        return new ExpressionState(xpathBuilder, var);
    }
   
    private ParserBuilder handle(ElementParserBuilder parent, LogicalExpr expr) {
        Object left = handleExpression(parent, expr.getLHS());
        Object right = handleExpression(parent, expr.getRHS());
       
        JBlock block = parent.getBody().getBlock();
       
        JVar b1 = ((ExpressionState) left).getVar();
        JVar b2 = ((ExpressionState) right).getVar();
       
        String op = expr.getOperator();
       
        JBlock newBlock;
        if (op.equals("and")) {
            newBlock = block._if(b1.cand(b2))._then();
        } else if (op.equals("or")) {
            newBlock = block._if(b1.cor(b2))._then();
        } else {
            throw new UnsupportedOperationException("Operator " + op + " is not supported");
        }
       
        return parent.newState(newBlock);
    }
   
    private ExpressionState handle(ElementParserBuilder xpathBuilder, FunctionCallExpr expr) {

        String name = "functValue" + varCount++;
        String functionName = expr.getFunctionName();
        JVar var;
        // See http://www.w3schools.com/xpath/xpath_functions.asp for a complete list
        if ("local-name".equals(functionName)) {
            var =  xpathBuilder.getBody().decl(stringType,
                                               name,
                                               xpathBuilder.getXSR().invoke("getLocalName"));
        } else if ("namespace-uri".equals(functionName)) {
            var =  xpathBuilder.getBody().decl(stringType,
                                               name,
                                               xpathBuilder.getXSR().invoke("getNamespaceURI"));
        } else {
            throw new XPathException("Function " + functionName + " is not understood!");
        }
       
        return new ExpressionState(xpathBuilder, var);
    }

    private ExpressionState handle(ElementParserBuilder parent, EqualityExpr expr) {
        ExpressionState left = (ExpressionState) handleExpression(parent, expr.getLHS());
        ExpressionState right = (ExpressionState) handleExpression(parent, expr.getRHS());
       
        JVar var = parent.getBody().decl(boolType,
                              "b" + varCount++,
                     left.getVar().invoke("equals").arg(right.getVar()));
       
        return new ExpressionState(parent, var);
    }

    private Object handle(ElementParserBuilder xpathBuilder, LocationPath path) {
        Object returnObj = xpathBuilder;
       
        // look for the next part on all child elements
        boolean globalElement = false;
        for (Iterator itr = path.getSteps().iterator(); itr.hasNext();) {
            Object o = itr.next();
           
            if (o instanceof NameStep) {
                returnObj = handleNameStep((ParserBuilder) returnObj, (NameStep) o, globalElement);
                globalElement = false;
            } else if (o instanceof AllNodeStep) {
                globalElement = true;
            } else if (o instanceof TextNodeStep) {
                returnObj = handleTextNodeStep((ParserBuilder) returnObj, (TextNodeStep) o);
            } else {
                throw new XPathException("Unsupported expression: " + o);
            }
        }
       
        return returnObj;
    }

    private ExpressionState handleTextNodeStep(ParserBuilder returnBuilder, TextNodeStep step) {
        JVar var = returnBuilder.as(String.class);
        return new ExpressionState(returnBuilder, var);
    }

    private Object handleNameStep(ParserBuilder returnBuilder, NameStep step, boolean globalElement) {
        String prefix = step.getPrefix();
        String ns = "";
        if (prefix != null && !prefix.equals("")) {
            ns = namespaceContext.get(prefix);
           
            if (ns == null) {
                throw new XPathException("Could not find namespace for prefix: " + prefix);
            }
        }
       
        QName n = new QName(ns, step.getLocalName());
       
        ElementParserBuilder elBuilder = ((ElementParserBuilder) returnBuilder);
        if (step.getAxis() == Axis.CHILD) {
            if (n.getLocalPart().equals("*")) {
                returnBuilder = elBuilder.expectAnyElement();
            } else if (globalElement) {
                returnBuilder = elBuilder.expectGlobalElement(n);
            } else {
                returnBuilder = elBuilder.expectElement(n);
            }
        } else if (step.getAxis() == Axis.ATTRIBUTE) {
            returnBuilder = elBuilder.expectAttribute(n);
        } else {
            throw new XPathException("Unsupported axis: " + step.getAxis());
        }
       
        return handlePredicates(returnBuilder, step.getPredicateSet().getPredicates());
    }

    private Object handle(ElementParserBuilder xpathBuilder, NumberExpr expr) {
  JBlock block = xpathBuilder.getBody().getBlock();
  JVar xsrVar = xpathBuilder.getXSR();
 
  JInvocation result = JExpr._this().invoke("incrementElementCount")
          .arg(xsrVar.invoke("getName"))
          .arg(xsrVar.invoke("getDepth"));
  JVar countVar = block.decl(intType, "count", result);
   
  JBlock then = block._if(countVar.eq(JExpr.lit((int) Double.valueOf(expr.getText()).doubleValue())))._then();
 
  return xpathBuilder.newState(then);
    }

    private Object handlePredicates(ParserBuilder returnBuilder, List<?> predicates) {
        Object returnObj = returnBuilder;
        for (Iterator<?> pitr = predicates.iterator(); pitr.hasNext();) {
            Predicate p = (Predicate) pitr.next();
           
            returnObj =
                handleExpression((ElementParserBuilder) returnObj, p.getExpr());
        }
        return returnObj;
    }

    public Map<String, String> getNamespaceContext() {
        return namespaceContext;
    }   

    public void setNamespaceContext(Map<String, String> namespaceContext) {
        this.namespaceContext = namespaceContext;
    }

    public void addPrefix(String prefix, String namespace) {
        if (namespaceContext == null) {
            namespaceContext = new HashMap<String, String>();
        }
        namespaceContext.put(prefix, namespace);
    }
   
    public void addAllPrefixes(Map<String, String> prefixes) {
        if (namespaceContext == null) {
            namespaceContext = new HashMap<String, String>();
        }
        namespaceContext.putAll(prefixes);
    }
   
    public static class ExpressionState {
        private JVar var;
        private ParserBuilder builder;

        public ExpressionState(ParserBuilder builder, JVar var) {
            this.builder = builder;
            this.var = var;
        }

        public ParserBuilder getBuilder() {
            return builder;
        }

        public void setBuilder(ParserBuilder builder) {
            this.builder = builder;
        }

        public JVar getVar() {
            return var;
        }

        public void setVar(JVar var) {
            this.var = var;
        }
       
    }
}
TOP

Related Classes of com.envoisolutions.sxc.xpath.XPathBuilder$ExpressionState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.