--- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java (working copy) @@ -22,52 +22,52 @@ import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.tagext.TagSupport; -import javax.xml.transform.TransformerException; import org.apache.taglibs.standard.util.EscapeXML; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; /** - * Tag handler for <out> in JSTL's XML library. - * TODO: should we rename this to OutSupport to match the tag name? + * Tag handler for <out> in JSTL's XML library. TODO: should we rename + * this to OutSupport to match the tag name? * * @author Shawn Bayern */ public abstract class ExprSupport extends TagSupport { - private XPath select; - protected boolean escapeXml = true; // tag attribute + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + protected boolean escapeXml = true; // tag attribute - @Override - public void release() { - super.release(); - select = null; - } + public ExprSupport() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - //********************************************************************* - // Tag logic + @Override + public void release() { + super.release(); + compiler = null; + select = null; + } - // applies XPath expression from 'select' and prints the result - @Override - public int doStartTag() throws JspException { - try { - XPathContext context = XalanUtil.getContext(this, pageContext); - String result = select.execute(context, context.getCurrentNode(), null).str(); - EscapeXML.emit(result, escapeXml, pageContext.getOut()); - return SKIP_BODY; - } catch (IOException ex) { - throw new JspTagException(ex.toString(), ex); - } catch (TransformerException e) { - throw new JspTagException(e); - } - } + // ********************************************************************* + // Tag logic - public void setSelect(String select) { - try { - this.select = new XPath(select, null, null, XPath.SELECT); - } catch (TransformerException e) { - throw new AssertionError(); - } - } + // applies XPath expression from 'select' and prints the result + @Override + public int doStartTag() throws JspException { + try { + String result = select.evaluateString(ForEachTag.getContext(this), pageContext); + EscapeXML.emit(result, escapeXml, pageContext.getOut()); + return SKIP_BODY; + } catch (IOException ex) { + throw new JspTagException(ex.toString(), ex); + } + } + + public void setSelect(String select) { + this.select = compiler.compile(select); + } } --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java (working copy) @@ -17,15 +17,15 @@ package org.apache.taglibs.standard.tag.common.xml; -import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.LoopTagSupport; -import javax.xml.transform.TransformerException; +import javax.servlet.jsp.tagext.Tag; +import javax.servlet.jsp.tagext.TagSupport; -import org.apache.xml.dtm.DTMIterator; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XObject; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; /** * Implementation of <x:forEach> tag using low-level Xalan API. @@ -35,95 +35,67 @@ */ public class ForEachTag extends LoopTagSupport { - private XPath select; - private XPathContext context; + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + private JSTLXPathContext context; - @Override - public void release() { - super.release(); - select = null; - context = null; - } + public ForEachTag() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - @Override - protected void prepare() throws JspTagException { - context = XalanUtil.getContext(this, pageContext); - try { - XObject nodes = select.execute(context, context.getCurrentNode(), null); + @Override + public void release() { + super.release(); + compiler = null; + select = null; + context = null; + } - // create an iterator over the returned nodes and push into the context - DTMIterator iterator = nodes.iter(); - context.pushContextNodeList(iterator); - } catch (TransformerException e) { - throw new JspTagException(e); - } - } + @Override + protected void prepare() throws JspTagException { + context = select.iterate(getContext(this), pageContext); + } - @Override - protected boolean hasNext() throws JspTagException { - DTMIterator iterator = context.getContextNodeList(); - return iterator.getCurrentPos() < iterator.getLength(); - } + @Override + protected boolean hasNext() throws JspTagException { + return context.hasNext(); + } - @Override - protected Object next() throws JspTagException { - DTMIterator iterator = context.getContextNodeList(); - int next = iterator.nextNode(); - context.pushCurrentNode(next); - return iterator.getDTM(next).getNode(next); - } + @Override + protected Object next() throws JspTagException { + return context.next(); + } - @Override - public int doAfterBody() throws JspException { - // pop the context node after executing the body - context.popCurrentNode(); - return super.doAfterBody(); - } + public void setSelect(String select) { + this.select = compiler.compile(select); + } - @Override - public void doFinally() { - // context might be null as prepare is not called if end < begin - if (context != null) { - // pop the list of nodes being iterated - context.popContextNodeList(); - context = null; - } - super.doFinally(); - } + public void setBegin(int begin) throws JspTagException { + this.beginSpecified = true; + this.begin = begin; + validateBegin(); + } - public void setSelect(String select) { - try { - this.select = new XPath(select, null, null, XPath.SELECT); - } catch (TransformerException e) { - throw new AssertionError(); - } - } + public void setEnd(int end) throws JspTagException { + this.endSpecified = true; + this.end = end; + validateEnd(); + } - public void setBegin(int begin) throws JspTagException { - this.beginSpecified = true; - this.begin = begin; - validateBegin(); - } + public void setStep(int step) throws JspTagException { + this.stepSpecified = true; + this.step = step; + validateStep(); + } - public void setEnd(int end) throws JspTagException { - this.endSpecified = true; - this.end = end; - validateEnd(); - } - - public void setStep(int step) throws JspTagException { - this.stepSpecified = true; - this.step = step; - validateStep(); - } - - /** - * Return the current XPath context to support expression evaluation in nested tags. - * - * @return the current XPath context - */ - XPathContext getContext() { - return context; - } + /* Retrieves the current context. */ + public static JSTLXPathContext getContext(Tag child) { + ForEachTag forEachTag = (ForEachTag) TagSupport.findAncestorWithClass(child, ForEachTag.class); + if (forEachTag == null) { + return null; + } else { + return forEachTag.context; + } + } } - --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java (working copy) @@ -19,43 +19,42 @@ import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.ConditionalTagSupport; -import javax.xml.transform.TransformerException; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; /** - *
Tag handler for <if> in JSTL's XML library.
+ *+ * Tag handler for <if> in JSTL's XML library. + *
* * @author Shawn Bayern */ public class IfTag extends ConditionalTagSupport { - private XPath select; + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + public IfTag() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - @Override - public void release() { - super.release(); - select = null; - } + @Override + public void release() { + super.release(); + compiler = null; + select = null; + } - @Override - protected boolean condition() throws JspTagException { - XPathContext context = XalanUtil.getContext(this, pageContext); - try { - return select.bool(context, context.getCurrentNode(), null); - } catch (TransformerException e) { - throw new JspTagException(e); - } - } + @Override + protected boolean condition() throws JspTagException { + return select.evaluateBoolean(ForEachTag.getContext(this), pageContext); + } - public void setSelect(String select) { - try { - this.select = new XPath(select, null, null, XPath.SELECT); - } catch (TransformerException e) { - throw new AssertionError(); - } - } + public void setSelect(String select) { + this.select = compiler.compile(select); + } } --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java (working copy) @@ -18,70 +18,73 @@ package org.apache.taglibs.standard.tag.common.xml; import javax.servlet.jsp.JspException; -import javax.servlet.jsp.JspTagException; +//import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.TagSupport; -import javax.xml.transform.TransformerException; +//import javax.xml.transform.TransformerException; import org.apache.taglibs.standard.tag.common.core.Util; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XObject; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; +//import org.apache.xpath.XPath; +//import org.apache.xpath.XPathContext; +//import org.apache.xpath.objects.XObject; /** - *Tag handler for <set> in JSTL's XML library.
+ *+ * Tag handler for <set> in JSTL's XML library. + *
* * @author Shawn Bayern */ public class SetTag extends TagSupport { - private XPath select; - private String var; - private int scope = PageContext.PAGE_SCOPE; + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + private String var; + private int scope = PageContext.PAGE_SCOPE; - //********************************************************************* - // Construction and initialization + // ********************************************************************* + // Construction and initialization - @Override - public void release() { - super.release(); - select = null; - var = null; - } + public SetTag() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - //********************************************************************* - // Tag logic + @Override + public void release() { + super.release(); + compiler = null; + select = null; + var = null; + } - // applies XPath expression from 'select' and stores the result in 'var' + // ********************************************************************* + // Tag logic - @Override - public int doStartTag() throws JspException { - try { - XPathContext context = XalanUtil.getContext(this, pageContext); - XObject result = select.execute(context, context.getCurrentNode(), null); - pageContext.setAttribute(var, XalanUtil.coerceToJava(result), scope); - return SKIP_BODY; - } catch (TransformerException e) { - throw new JspTagException(e); - } - } + // applies XPath expression from 'select' and stores the result in 'var' - //********************************************************************* - // Attribute accessors + @Override + public int doStartTag() throws JspException { + Object result = select.evaluateObject(ForEachTag.getContext(this), pageContext); + pageContext.setAttribute(var, result, scope); + return SKIP_BODY; + } - public void setSelect(String select) { - try { - this.select = new XPath(select, null, null, XPath.SELECT); - } catch (TransformerException e) { - throw new AssertionError(); - } - } + // ********************************************************************* + // Attribute accessors - public void setVar(String var) { - this.var = var; - } + public void setSelect(String select) { + this.select = compiler.compile(select); + } - public void setScope(String scope) { - this.scope = Util.getScope(scope); - } + public void setVar(String var) { + this.var = var; + } + + public void setScope(String scope) { + this.scope = Util.getScope(scope); + } } --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java (working copy) @@ -18,43 +18,43 @@ package org.apache.taglibs.standard.tag.common.xml; import javax.servlet.jsp.JspTagException; -import javax.xml.transform.TransformerException; import org.apache.taglibs.standard.tag.common.core.WhenTagSupport; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; /** - *Tag handler for <if> in JSTL's XML library.
+ *+ * Tag handler for <if> in JSTL's XML library. + *
* * @author Shawn Bayern */ public class WhenTag extends WhenTagSupport { - private XPath select; + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; - @Override - public void release() { - super.release(); - select = null; - } + public WhenTag() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - @Override - protected boolean condition() throws JspTagException { - XPathContext context = XalanUtil.getContext(this, pageContext); - try { - return select.bool(context, context.getCurrentNode(), null); - } catch (TransformerException e) { - throw new JspTagException(e); - } - } + @Override + public void release() { + super.release(); + compiler = null; + select = null; + } - public void setSelect(String select) { - try { - this.select = new XPath(select, null, null, XPath.SELECT); - } catch (TransformerException e) { - throw new AssertionError(); - } - } + @Override + protected boolean condition() throws JspTagException { + return select.evaluateBoolean(ForEachTag.getContext(this), pageContext); + } + + public void setSelect(String select) { + this.select = compiler.compile(select); + } } --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java (revision 1817510) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java (working copy) @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.taglibs.standard.tag.common.xml; - -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.tagext.Tag; -import javax.servlet.jsp.tagext.TagSupport; -import javax.xml.transform.TransformerException; - -import org.apache.taglibs.standard.util.XmlUtil; -import org.apache.xpath.VariableStack; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XBoolean; -import org.apache.xpath.objects.XNodeSet; -import org.apache.xpath.objects.XNumber; -import org.apache.xpath.objects.XObject; -import org.apache.xpath.objects.XString; -import org.w3c.dom.NodeList; - -/** - */ -public class XalanUtil { - /** - * Return the XPathContext to be used for evaluating expressions. - * - * If the child is nested withing a forEach tag its iteration context is used. - * Otherwise, a new context is created based on an empty Document. - * - * @param child the tag whose context should be returned - * @param pageContext the current page context - * @return the XPath evaluation context - */ - public static XPathContext getContext(Tag child, PageContext pageContext) { - // if within a forEach tag, use its context - ForEachTag forEachTag = (ForEachTag) TagSupport.findAncestorWithClass(child, ForEachTag.class); - if (forEachTag != null) { - return forEachTag.getContext(); - } - - // otherwise, create a new context referring to an empty document - XPathContext context = new XPathContext(false); - VariableStack variableStack = new JSTLVariableStack(pageContext); - context.setVarStack(variableStack); - int dtm = context.getDTMHandleFromNode(XmlUtil.newEmptyDocument()); - context.pushCurrentNodeAndExpression(dtm, dtm); - return context; - } - - /** - * Return the Java value corresponding to an XPath result. - * - * @param xo the XPath type - * @return the corresponding Java value per the JSTL mapping rules - * @throws TransformerException if there was a problem converting the type - */ - static Object coerceToJava(XObject xo) throws TransformerException { - if (xo instanceof XBoolean) { - return xo.bool(); - } else if (xo instanceof XNumber) { - return xo.num(); - } else if (xo instanceof XString) { - return xo.str(); - } else if (xo instanceof XNodeSet) { - NodeList nodes = xo.nodelist(); - // if there is only one node in the nodeset return it rather than the list - if (nodes.getLength() == 1) { - return nodes.item(0); - } else { - return nodes; - } - } else { - // unexpected result type - throw new AssertionError(); - } - } -} --- impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java (working copy) @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.taglibs.standard.xpath; + +/** + */ +public class InvalidXPathException extends RuntimeException { + public InvalidXPathException() { + } + + public InvalidXPathException(String s) { + super(s); + } + + public InvalidXPathException(String s, Throwable throwable) { + super(s, throwable); + } + + public InvalidXPathException(Throwable throwable) { + super(throwable); + } +} +native --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java (working copy) @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.taglibs.standard.xpath; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.PageContext; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathVariableResolver; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + */ +public class JSTLVariableResolver implements XPathVariableResolver, NamespaceContext { + + private static enum Scope { + JSP, PARAM, HEADER, COOKIE, INITPARAM, PAGE, REQUEST, SESSION, APPLICATION + } + + // Namespace URIs for JSTL implicit variables + private static final String PARAM_NS_URL = "http://java.sun.com/jstl/xpath/param"; + private static final String HEADER_NS_URL = "http://java.sun.com/jstl/xpath/header"; + private static final String COOKIE_NS_URL = "http://java.sun.com/jstl/xpath/cookie"; + private static final String INITPARAM_NS_URL = "http://java.sun.com/jstl/xpath/initParam"; + private static final String PAGE_NS_URL = "http://java.sun.com/jstl/xpath/page"; + private static final String REQUEST_NS_URL = "http://java.sun.com/jstl/xpath/request"; + private static final String SESSION_NS_URL = "http://java.sun.com/jstl/xpath/session"; + private static final String APP_NS_URL = "http://java.sun.com/jstl/xpath/app"; + + // Prefixes for JSTL implicit variables + private static final String PARAM_PREFIX = "param"; + private static final String HEADER_PREFIX = "header"; + private static final String COOKIE_PREFIX = "cookie"; + private static final String INITPARAM_PREFIX = "initParam"; + private static final String PAGE_PREFIX = "pageScope"; + private static final String REQUEST_PREFIX = "requestScope"; + private static final String SESSION_PREFIX = "sessionScope"; + private static final String APP_PREFIX = "applicationScope"; + + // map prefixes to namespaces + private static final Map