Index: impl/src/test/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpressionTest.java =================================================================== --- impl/src/test/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpressionTest.java (revision 0) +++ impl/src/test/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpressionTest.java (revision 0) @@ -0,0 +1,94 @@ +/* + * 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.jaxp; + +import java.io.InputStream; + +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.apache.taglibs.standard.xpath.JSTLVariableResolver; +import org.apache.taglibs.standard.xpath.xalan.XalanXPathExpressionTest; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.w3c.dom.Document; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +/** + */ +public class JAXPXPathExpressionTest { + + private XPath xpath; + private JSTLVariableResolver resolver; + private PageContext pageContext; + + private static Document d; + + @BeforeClass + public static void loadTestXML() throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + InputStream is = XalanXPathExpressionTest.class.getResourceAsStream("test.xml"); + try { + d = db.parse(is); + } finally { + is.close(); + } + } + + @Before + public void setup() { + XPathFactory factory = XPathFactory.newInstance(); + xpath = factory.newXPath(); + resolver = new JSTLVariableResolver(); + xpath.setXPathVariableResolver(resolver); + pageContext = createMock(PageContext.class); + + } + + @Ignore + @Test + public void testBooleanExpressionReturnsBoolean() throws JspTagException, XPathExpressionException { + XPathExpression exp = xpath.compile("true()"); + JAXPXPathExpression xpe = new JAXPXPathExpression(exp, resolver); + Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, null)); + } + @Test + public void testSelectTextFromDOM() throws Exception { + XPathExpression exp = xpath.compile("string($a/root/b/hello)"); + JAXPXPathExpression xpe = new JAXPXPathExpression(exp, resolver); + expect(pageContext.findAttribute("a")).andReturn(d); + replay(pageContext); + Assert.assertEquals("world", xpe.evaluateString(null, pageContext)); + verify(pageContext); + } +} Index: impl/src/test/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpressionTest.java =================================================================== --- impl/src/test/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpressionTest.java (revision 0) +++ impl/src/test/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpressionTest.java (revision 0) @@ -0,0 +1,169 @@ +/* + * 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.xalan; + +import java.io.InputStream; +import java.util.concurrent.Callable; + +import javax.servlet.jsp.PageContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.apache.xpath.XPath; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +/** + */ +public class XalanXPathExpressionTest { + private PageContext pageContext; + private static Document d; + private static DocumentBuilder db; + + @BeforeClass + public static void loadTestXML() throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + db = dbf.newDocumentBuilder(); + InputStream is = XalanXPathExpressionTest.class.getResourceAsStream("test.xml"); + try { + d = db.parse(is); + } finally { + is.close(); + } + } + + @Before + public void setup() { + pageContext = createMock(PageContext.class); + } + + @Test + public void testBooleanExpressionReturnsBoolean() throws Exception { + XPath xpath = new XPath("true()", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, null)); + } + + @Test + public void testStringExpressionReturnsString() throws Exception { + XPath xpath = new XPath("\"hello\"", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + Assert.assertEquals("hello", xpe.evaluateObject(null, null)); + } + + @Test + public void testNumberExpressionReturnsNumber() throws Exception { + XPath xpath = new XPath("1234", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + Assert.assertEquals(1234.0, xpe.evaluateObject(null, null)); + } + + @Test + public void testBooleanVariable() throws Exception { + XPath xpath = new XPath("$a", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + expect(pageContext.findAttribute("a")).andReturn(Boolean.TRUE); + replay(pageContext); + Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, pageContext)); + verify(pageContext); + } + + @Test + public void testNumberVariable() throws Exception { + XPath xpath = new XPath("$a", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + Number value = 1234.5; + expect(pageContext.findAttribute("a")).andReturn(value); + replay(pageContext); + Assert.assertEquals(value, xpe.evaluateObject(null, pageContext)); + verify(pageContext); + } + + @Test + public void testStringVariable() throws Exception { + XPath xpath = new XPath("$a", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + String value = "Hello"; + expect(pageContext.findAttribute("a")).andReturn(value); + replay(pageContext); + Assert.assertEquals(value, xpe.evaluateObject(null, pageContext)); + verify(pageContext); + } + + @Test + public void testSelectTextFromDOM() throws Exception { + XPath xpath = new XPath("string($a/root/b/hello)", null, null, XPath.SELECT); + XalanXPathExpression xpe = new XalanXPathExpression(xpath); + expect(pageContext.findAttribute("a")).andReturn(d); + replay(pageContext); + Assert.assertEquals("world", xpe.evaluateObject(null, pageContext)); + verify(pageContext); + } + + @Ignore + @Test + public void testIterationPerformance() throws Exception { + int size = 200000; + System.out.println("Creating DOM"); + d = db.newDocument(); + Element root = d.createElement("root"); + d.appendChild(root); + for (int i = 0; i < size; i++) { + Element a = d.createElement("a"); + root.appendChild(a); + Element b = d.createElement("b"); + b.setTextContent(Integer.toString(i)); + a.appendChild(b); + } + System.out.println("DOM created"); + expect(pageContext.findAttribute("doc")).andStubReturn(d); + replay(pageContext); + final XalanXPathExpression forEach = new XalanXPathExpression(new XPath("$doc/root/a", null, null, XPath.SELECT)); + final XalanXPathExpression inner = new XalanXPathExpression(new XPath("b", null, null, XPath.SELECT)); + Callable test = new Callable() { + public Long call() throws Exception { + long time = -System.nanoTime(); + JSTLXPathContext iterator = forEach.iterate(null, pageContext); + while (iterator.hasNext()) { + Object node = iterator.next(); + String s = inner.evaluateString(iterator, pageContext); + } + time += System.nanoTime(); + return time; + } + }; + // warm up the JIT + test.call(); + System.out.println("JIT Primed, starting test"); + long time = test.call(); + System.out.println("time = " + time/1000000+"ms."); + System.out.flush(); + } +} Index: impl/src/test/resources/org/apache/taglibs/standard/xpath/xalan/test.xml =================================================================== --- impl/src/test/resources/org/apache/taglibs/standard/xpath/xalan/test.xml (revision 0) +++ impl/src/test/resources/org/apache/taglibs/standard/xpath/xalan/test.xml (revision 0) @@ -0,0 +1,10 @@ + + + one + two + three + + + world + + \ No newline at end of file Index: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathExpression.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathExpression.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathExpression.java (revision 0) @@ -0,0 +1,33 @@ +/* + * 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.jsp.JspTagException; +import javax.servlet.jsp.PageContext; + +/** + */ +public interface JSTLXPathExpression { + + boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException; + + String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException; + + Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException; + + JSTLXPathContext iterate(JSTLXPathContext context, PageContext pageContext) throws JspTagException; +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathFactory.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathFactory.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathFactory.java (revision 0) @@ -0,0 +1,42 @@ +/* + * 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.jaxp; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; + +import org.apache.taglibs.standard.xpath.JSTLVariableResolver; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; + +/** + */ +public class JAXPXPathFactory extends JSTLXPathFactory { + private static final XPathFactory xpf = XPathFactory.newInstance(); + + @Override + public JSTLXPathCompiler newCompiler() { + XPath xpath; + synchronized (xpf) { + xpath = xpf.newXPath(); + } + JSTLVariableResolver resolver = new JSTLVariableResolver(); + xpath.setXPathVariableResolver(resolver); + xpath.setNamespaceContext(resolver); + return new JAXPXPathCompiler(xpath); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathCompiler.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathCompiler.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathCompiler.java (revision 0) @@ -0,0 +1,44 @@ +/* + * 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.jaxp; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; + +import org.apache.taglibs.standard.xpath.InvalidXPathException; +import org.apache.taglibs.standard.xpath.JSTLVariableResolver; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; + +/** + */ +public class JAXPXPathCompiler implements JSTLXPathCompiler { + private final XPath xpath; + + public JAXPXPathCompiler(XPath xpath) { + this.xpath = xpath; + } + + public JSTLXPathExpression compile(String select) { + try { + JSTLVariableResolver resolver = (JSTLVariableResolver) xpath.getXPathVariableResolver(); + return new JAXPXPathExpression(xpath.compile(select), resolver); + } catch (XPathExpressionException e) { + throw new InvalidXPathException(e); + } + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpression.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpression.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpression.java (revision 0) @@ -0,0 +1,69 @@ +/* + * 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.jaxp; + +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; + +import org.apache.taglibs.standard.xpath.JSTLVariableResolver; +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + */ +public class JAXPXPathExpression implements JSTLXPathExpression { + private final XPathExpression expr; + private final JSTLVariableResolver resolver; + + public JAXPXPathExpression(XPathExpression expr, JSTLVariableResolver resolver) { + this.expr = expr; + this.resolver = resolver; + } + + public boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + return (Boolean) evaluate(context, pageContext, XPathConstants.BOOLEAN); + } + + public String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + return (String) evaluate(context, pageContext, XPathConstants.STRING); + } + + public Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + return evaluate(context, pageContext, XPathConstants.NODE); + } + + public JSTLXPathContext iterate(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + NodeList nodes = (NodeList) evaluate(context, pageContext, XPathConstants.NODESET); + return new JAXPXPathContext(nodes); + } + + private Object evaluate(JSTLXPathContext context, PageContext pageContext, QName resultType) throws JspTagException { + resolver.setPageContext(pageContext); + Node contextNode = (context == null) ? null : ((JAXPXPathContext) context).current(); + try { + return expr.evaluate(contextNode, resultType); + } catch (XPathExpressionException e) { + throw new JspTagException(e); + } + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathContext.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathContext.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathContext.java (revision 0) @@ -0,0 +1,44 @@ +/* + * 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.jaxp; + +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + */ +public class JAXPXPathContext implements JSTLXPathContext { + private final NodeList nodes; + private int index; + + public JAXPXPathContext(NodeList nodes) { + this.nodes = nodes; + } + + public boolean hasNext() { + return index < nodes.getLength(); + } + + public Object next() { + return nodes.item(index++); + } + + Node current() { + return nodes.item(index); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathFactory.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathFactory.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathFactory.java (revision 0) @@ -0,0 +1,29 @@ +/* + * 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.xalan; + +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; + +/** + */ +public class XalanXPathFactory extends JSTLXPathFactory { + @Override + public JSTLXPathCompiler newCompiler() { + return new XalanXPathCompiler(); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathCompiler.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathCompiler.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathCompiler.java (revision 0) @@ -0,0 +1,37 @@ +/* + * 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.xalan; + +import javax.xml.transform.TransformerException; + +import org.apache.taglibs.standard.xpath.InvalidXPathException; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.xpath.XPath; + +/** + */ +public class XalanXPathCompiler implements JSTLXPathCompiler { + public JSTLXPathExpression compile(String expression) throws InvalidXPathException { + try { + XPath xpath = new XPath(expression, null, null, XPath.SELECT); + return new XalanXPathExpression(xpath); + } catch (TransformerException e) { + throw new InvalidXPathException(e); + } + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/JSTLVariableStack.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/JSTLVariableStack.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/JSTLVariableStack.java (revision 0) @@ -0,0 +1,61 @@ +/* + * 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.xalan; + +import javax.servlet.jsp.PageContext; +import javax.xml.XMLConstants; +import javax.xml.transform.TransformerException; + +import org.apache.taglibs.standard.xpath.JSTLVariableResolver; +import org.apache.xml.utils.QName; +import org.apache.xpath.VariableStack; +import org.apache.xpath.XPathContext; +import org.apache.xpath.objects.XObject; +import org.apache.xpath.objects.XObjectFactory; + +/** + */ +public class JSTLVariableStack extends VariableStack { + + private final JSTLVariableResolver resolver; + + public JSTLVariableStack(PageContext pageContext) { + super(2); + resolver = new JSTLVariableResolver(); + resolver.setPageContext(pageContext); + } + + @Override + public XObject getVariableOrParam(XPathContext xctxt, QName qname) throws TransformerException { + String uri = qname.getNamespaceURI(); + if (uri == null) { + uri = XMLConstants.NULL_NS_URI; + } + String namespaceURI = resolver.getNamespaceURI(uri); + String localPart = qname.getLocalPart(); + javax.xml.namespace.QName name = new javax.xml.namespace.QName(namespaceURI, localPart); + Object value = resolver.resolveVariable(name); + if (value == null) { + throw new TransformerException("Variable " + qname + " not found"); + } + return coerceToXPath(value, xctxt); + } + + XObject coerceToXPath(Object value, XPathContext xctxt) { + return XObjectFactory.create(value, xctxt); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpression.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpression.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpression.java (revision 0) @@ -0,0 +1,152 @@ +/* + * 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.xalan; + +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.xpath.VariableStack; +import org.apache.xpath.XPath; +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.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + */ +public class XalanXPathExpression implements JSTLXPathExpression { + private final XPath xpath; + private static final DocumentBuilderFactory dbf; + + static { + dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + } + + public XalanXPathExpression(XPath xpath) { + this.xpath = xpath; + } + + public boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + try { + return evaluate(context, pageContext).bool(); + } catch (TransformerException e) { + throw new JspTagException(e); + } + } + + public String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + try { + return evaluate(context, pageContext).str(); + } catch (TransformerException e) { + throw new JspTagException(e); + } + } + + public Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException { + try { + XObject result = evaluate(context, pageContext); + return coerceToJava(result); + } catch (TransformerException e) { + throw new JspTagException(e); + } + } + + public JSTLXPathContext iterate(JSTLXPathContext jstlContext, PageContext pageContext) throws JspTagException { + XPathContext xpathContext; + int node; + if (jstlContext == null) { + xpathContext = newContext(pageContext); + Node root = getEmptyDocument(); + node = xpathContext.getDTMHandleFromNode(root); + } else { + XalanXPathContext context = (XalanXPathContext) jstlContext; + xpathContext = context.getContext(); + node = context.getCurrentNode(); + } + try { + XObject result = xpath.execute(xpathContext, node, null); + return new XalanXPathContext(xpathContext, result); + } catch (TransformerException e) { + throw new JspTagException(e); + } + } + + XObject evaluate(JSTLXPathContext jstlContext, PageContext pageContext) throws TransformerException { + XPathContext xpathContext; + int dtm; + if (jstlContext == null) { + xpathContext = newContext(pageContext); + Node node = getEmptyDocument(); + dtm = xpathContext.getDTMHandleFromNode(node); + } else { + XalanXPathContext context = (XalanXPathContext) jstlContext; + xpathContext = context.getContext(); + dtm = context.getCurrentNode(); + } + return xpath.execute(xpathContext, dtm, null); + } + + XPathContext newContext(PageContext pageContext) { + XPathContext context = new XPathContext(false); + VariableStack variableStack = new JSTLVariableStack(pageContext); + context.setVarStack(variableStack); + return context; + } + + 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 that rather than the list + if (nodes.getLength() == 1) { + return nodes.item(0); + } else { + return nodes; + } + } else { + // unexpected result type + throw new AssertionError(); + } + } + + Document getEmptyDocument() { + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + return db.newDocument(); + } catch (ParserConfigurationException e) { + throw new AssertionError(); + } + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathContext.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathContext.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathContext.java (revision 0) @@ -0,0 +1,53 @@ +/* + * 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.xalan; + +import javax.xml.transform.TransformerException; + +import org.apache.taglibs.standard.xpath.JSTLXPathContext; +import org.apache.xml.dtm.DTMIterator; +import org.apache.xpath.XPathContext; +import org.apache.xpath.objects.XObject; + +/** + */ +public class XalanXPathContext implements JSTLXPathContext { + private final XPathContext context; + private final DTMIterator iterator; + + public XalanXPathContext(XPathContext context, XObject nodes) throws TransformerException { + this.context = context; + iterator = nodes.iter(); + } + + public boolean hasNext() { + return iterator.getCurrentPos() < iterator.getLength(); + } + + public Object next() { + int next = iterator.nextNode(); + return iterator.getDTM(next).getNode(next); + } + + XPathContext getContext() { + return context; + } + + int getCurrentNode() { + return iterator.getCurrentNode(); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java (revision 0) @@ -0,0 +1,163 @@ +/* + * 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 NAMESPACES; + + static { + NAMESPACES = new HashMap(8); + NAMESPACES.put(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI); + NAMESPACES.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI); + NAMESPACES.put(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI); + NAMESPACES.put(PARAM_PREFIX, PARAM_NS_URL); + NAMESPACES.put(HEADER_PREFIX, HEADER_NS_URL); + NAMESPACES.put(COOKIE_PREFIX, COOKIE_NS_URL); + NAMESPACES.put(INITPARAM_PREFIX, INITPARAM_NS_URL); + NAMESPACES.put(PAGE_PREFIX, PAGE_NS_URL); + NAMESPACES.put(REQUEST_PREFIX, REQUEST_NS_URL); + NAMESPACES.put(SESSION_PREFIX, SESSION_NS_URL); + NAMESPACES.put(APP_PREFIX, APP_NS_URL); + } + + // map namespaces to scopes + private static final Map SCOPES; + + static { + SCOPES = new HashMap(8); + SCOPES.put(XMLConstants.NULL_NS_URI, Scope.JSP); + SCOPES.put(PARAM_NS_URL, Scope.PARAM); + SCOPES.put(HEADER_NS_URL, Scope.HEADER); + SCOPES.put(COOKIE_NS_URL, Scope.COOKIE); + SCOPES.put(INITPARAM_NS_URL, Scope.INITPARAM); + SCOPES.put(PAGE_NS_URL, Scope.PAGE); + SCOPES.put(REQUEST_NS_URL, Scope.REQUEST); + SCOPES.put(SESSION_NS_URL, Scope.SESSION); + SCOPES.put(APP_NS_URL, Scope.APPLICATION); + } + + + private PageContext pageContext; + + public void setPageContext(PageContext pageContext) { + this.pageContext = pageContext; + } + + public Object resolveVariable(QName variableName) { + String name = variableName.getLocalPart(); + Scope scope = SCOPES.get(variableName.getNamespaceURI()); + if (scope == null) { + return null; + } + switch (scope) { + case JSP: + return pageContext.findAttribute(name); + case PARAM: + return pageContext.getRequest().getParameter(name); + case HEADER: + return ((HttpServletRequest) pageContext.getRequest()).getHeader(name); + case COOKIE: + Cookie[] cookies = ((HttpServletRequest) pageContext.getRequest()).getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(name)) { + return cookie.getValue(); + } + } + } + return null; + case INITPARAM: + return pageContext.getServletContext().getInitParameter(name); + case PAGE: + return pageContext.getAttribute(name, PageContext.PAGE_SCOPE); + case REQUEST: + return pageContext.getAttribute(name, PageContext.REQUEST_SCOPE); + case SESSION: + return pageContext.getAttribute(name, PageContext.SESSION_SCOPE); + case APPLICATION: + return pageContext.getAttribute(name, PageContext.APPLICATION_SCOPE); + default: + throw new AssertionError(); + } + } + + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new IllegalArgumentException("prefix is null"); + } + String uri = NAMESPACES.get(prefix); + if (uri != null) { + return uri; + } + return XMLConstants.NULL_NS_URI; + } + + public String getPrefix(String namespaceURI) { + throw new UnsupportedOperationException(); + } + + public Iterator getPrefixes(String namespaceURI) { + throw new UnsupportedOperationException(); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathContext.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathContext.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathContext.java (revision 0) @@ -0,0 +1,24 @@ +/* + * 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 interface JSTLXPathContext { + boolean hasNext(); + Object next(); +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathFactory.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathFactory.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathFactory.java (revision 0) @@ -0,0 +1,32 @@ +/* + * 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 org.apache.taglibs.standard.xpath.xalan.XalanXPathFactory; + +/** + */ +public abstract class JSTLXPathFactory { + + private static final JSTLXPathFactory factory = new XalanXPathFactory(); + + public static JSTLXPathFactory getFactory() { + return factory; + } + + public abstract JSTLXPathCompiler newCompiler(); +} Property changes on: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathFactory.java ___________________________________________________________________ Added: svn:eol-style + native Index: impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java (revision 0) @@ -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); + } +} Index: impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathCompiler.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathCompiler.java (revision 0) +++ impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathCompiler.java (revision 0) @@ -0,0 +1,31 @@ +/* + * 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 interface JSTLXPathCompiler { + + /** + * Pre-compiles an XPath expression for future evaluation; + * + * @param xpath the xpath to compile + * @return an JSTLXPathExpression that can be used to evaluate the XPath + * @throws InvalidXPathException if the supplied XPath is not valid + */ + JSTLXPathExpression compile(String xpath) throws InvalidXPathException; +} Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java (working copy) @@ -1,896 +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 java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Vector; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.jsp.JspTagException; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.tagext.Tag; -import javax.servlet.jsp.tagext.TagSupport; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.TransformerException; - -import org.apache.taglibs.standard.resources.Resources; -import org.apache.xml.utils.QName; -import org.apache.xpath.VariableStack; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XBoolean; -import org.apache.xpath.objects.XNodeSetForDOM; -import org.apache.xpath.objects.XNumber; -import org.apache.xpath.objects.XObject; -import org.apache.xpath.objects.XString; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - *

Support for tag handlers that evaluate XPath expressions.

- * - * @author Shawn Bayern - * @author Ramesh Mandava ( ramesh.mandava@sun.com ) - * @author Pierre Delisle ( pierre.delisle@sun.com ) - */ -// would ideally be a base class, but some of our user handlers already -// have their own parents -public class XPathUtil { - - //********************************************************************* - // Constructor - - /** - * Constructs a new XPathUtil object associated with the given - * PageContext. - */ - public XPathUtil(PageContext pc) { - pageContext = pc; - } - - int globalVarSize = 0; - - public Vector getVariableQNames() { - - globalVarSize = 0; - Vector variableVector = new Vector(); - // Now construct attributes in different scopes - Enumeration enum_ = pageContext.getAttributeNamesInScope( - PageContext.PAGE_SCOPE); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(PAGE_NS_URL, PAGE_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - - variableVector.addElement(new QName(null, varName)); - globalVarSize++; - } - enum_ = pageContext.getAttributeNamesInScope( - PageContext.REQUEST_SCOPE); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(REQUEST_NS_URL, REQUEST_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - variableVector.addElement(new QName(null, varName)); - globalVarSize++; - } - - if (pageContext.getSession() != null) { - // we may have a page directive preventing session creation/access - // do not attempt to retrieve attribute names in session scope - // @see [ http://issues.apache.org/bugzilla/show_bug.cgi?id=35216 ] - enum_ = pageContext.getAttributeNamesInScope( - PageContext.SESSION_SCOPE); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(SESSION_NS_URL, SESSION_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - variableVector.addElement(new QName(null, varName)); - globalVarSize++; - } - } - - enum_ = pageContext.getAttributeNamesInScope( - PageContext.APPLICATION_SCOPE); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(APP_NS_URL, APP_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - variableVector.addElement(new QName(null, varName)); - globalVarSize++; - } - enum_ = pageContext.getRequest().getParameterNames(); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(PARAM_NS_URL, PARAM_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - } - enum_ = pageContext.getServletContext().getInitParameterNames(); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(INITPARAM_NS_URL, INITPARAM_P, varName); - //Adding both namespace qualified QName and just localName - variableVector.addElement(varQName); - globalVarSize++; - } - enum_ = ((HttpServletRequest) pageContext.getRequest()).getHeaderNames(); - while (enum_.hasMoreElements()) { - String varName = (String) enum_.nextElement(); - QName varQName = new QName(HEADER_NS_URL, HEADER_P, varName); - //Adding namespace qualified QName - variableVector.addElement(varQName); - globalVarSize++; - } - Cookie[] c = ((HttpServletRequest) pageContext.getRequest()).getCookies(); - if (c != null) { - for (int i = 0; i < c.length; i++) { - String varName = c[i].getName(); - QName varQName = new QName(COOKIE_NS_URL, COOKIE_P, varName); - //Adding namespace qualified QName - variableVector.addElement(varQName); - globalVarSize++; - } - } - - return variableVector; - - } - - //********************************************************************* - // Support for JSTL variable resolution - - // The URLs - 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"; - private static final String PARAM_NS_URL - = "http://java.sun.com/jstl/xpath/param"; - private static final String INITPARAM_NS_URL - = "http://java.sun.com/jstl/xpath/initParam"; - private static final String COOKIE_NS_URL - = "http://java.sun.com/jstl/xpath/cookie"; - private static final String HEADER_NS_URL - = "http://java.sun.com/jstl/xpath/header"; - - // The prefixes - private static final String PAGE_P = "pageScope"; - private static final String REQUEST_P = "requestScope"; - private static final String SESSION_P = "sessionScope"; - private static final String APP_P = "applicationScope"; - private static final String PARAM_P = "param"; - private static final String INITPARAM_P = "initParam"; - private static final String COOKIE_P = "cookie"; - private static final String HEADER_P = "header"; - - /** - * org.apache.xpath.VariableStack defines a class to keep track of a stack - * for template arguments and variables. - * JstlVariableContext customizes it so it handles JSTL custom - * variable-mapping rules. - */ - protected class JstlVariableContext extends org.apache.xpath.VariableStack { - - public JstlVariableContext() { - super(); - } - - /** - * Get a variable as an XPath object based on it's qualified name. - * We override the base class method so JSTL's custom variable-mapping - * rules can be applied. - * - * @param xctxt The XPath context. @@@ we don't use it... - * (from xalan: which must be passed in order to lazy evaluate variables.) - * @param qname The qualified name of the variable. - */ - @Override - public XObject getVariableOrParam( - XPathContext xctxt, - org.apache.xml.utils.QName qname) - throws javax.xml.transform.TransformerException, UnresolvableException { - //p( "***********************************getVariableOrParam begin****"); - String namespace = qname.getNamespaceURI(); - String prefix = qname.getPrefix(); - String localName = qname.getLocalName(); - - //p("namespace:prefix:localname=>"+ namespace - // + ":" + prefix +":" + localName ); - - try { - Object varObject = getVariableValue(namespace, prefix, localName); - - - //XObject varObject = myvs.getVariableOrParam( xpathSupport, varQName); - XObject newXObject = new XObject(varObject); - - if (Class.forName("org.w3c.dom.Document").isInstance(varObject)) { - - NodeList nl = ((Document) varObject).getChildNodes(); - // To allow non-welformed document - Vector nodeVector = new Vector(); - for (int i = 0; i < nl.getLength(); i++) { - Node currNode = nl.item(i); - if (currNode.getNodeType() == Node.ELEMENT_NODE) { - nodeVector.addElement(currNode); - } - } - JSTLNodeList jstlNodeList = new JSTLNodeList(nodeVector); - newXObject = new XNodeSetForDOM(jstlNodeList, xctxt); - - return newXObject; - - } - if (Class.forName( - "org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance( - varObject)) { - JSTLNodeList jstlNodeList = (JSTLNodeList) varObject; - if ((jstlNodeList.getLength() == 1) && - (!Class.forName("org.w3c.dom.Node").isInstance(jstlNodeList.elementAt(0)))) { - varObject = jstlNodeList.elementAt(0); - //Now we need to allow this primitive type to be coverted - // to type which Xalan XPath understands - } else { - return new XNodeSetForDOM(jstlNodeList, xctxt); - } - } - if (Class.forName("org.w3c.dom.Node").isInstance(varObject)) { - newXObject = new XNodeSetForDOM(new JSTLNodeList((Node) varObject), xctxt); - } else if (Class.forName("java.lang.String").isInstance(varObject)) { - newXObject = new XString((String) varObject); - } else if (Class.forName("java.lang.Boolean").isInstance(varObject)) { - newXObject = new XBoolean((Boolean) varObject); - } else if (Class.forName("java.lang.Number").isInstance(varObject)) { - newXObject = new XNumber((Number) varObject); - } - - return newXObject; - // myvs.setGlobalVariable( i, newXObject ); - } catch (ClassNotFoundException cnfe) { - // This shouldn't happen (TODO: LOG) - System.out.println("CLASS NOT FOUND EXCEPTION :" + cnfe); - } - //System.out.println("*****getVariableOrParam returning *null*" ); - return null; - } - - /** - * Retrieve an XPath's variable value using JSTL's custom - * variable-mapping rules - */ - public Object getVariableValue( - String namespace, - String prefix, - String localName) - throws UnresolvableException { - // p("resolving: ns=" + namespace + " prefix=" + prefix + " localName=" + localName); - // We can match on namespace with Xalan but leaving as is - // [ I 'd prefer to match on namespace, but this doesn't appear - // to work in Jaxen] - if (prefix == null || prefix.equals("")) { - return notNull( - pageContext.findAttribute(localName), - prefix, - localName); - } else if (prefix.equals(PAGE_P)) { - return notNull( - pageContext.getAttribute(localName, PageContext.PAGE_SCOPE), - prefix, - localName); - } else if (prefix.equals(REQUEST_P)) { - return notNull( - pageContext.getAttribute(localName, - PageContext.REQUEST_SCOPE), - prefix, - localName); - } else if (prefix.equals(SESSION_P)) { - return notNull( - pageContext.getAttribute(localName, - PageContext.SESSION_SCOPE), - prefix, - localName); - } else if (prefix.equals(APP_P)) { - return notNull( - pageContext.getAttribute(localName, - PageContext.APPLICATION_SCOPE), - prefix, - localName); - } else if (prefix.equals(PARAM_P)) { - return notNull( - pageContext.getRequest().getParameter(localName), - prefix, - localName); - } else if (prefix.equals(INITPARAM_P)) { - return notNull( - pageContext.getServletContext(). - getInitParameter(localName), - prefix, - localName); - } else if (prefix.equals(HEADER_P)) { - HttpServletRequest hsr = - (HttpServletRequest) pageContext.getRequest(); - return notNull( - hsr.getHeader(localName), - prefix, - localName); - } else if (prefix.equals(COOKIE_P)) { - HttpServletRequest hsr = - (HttpServletRequest) pageContext.getRequest(); - Cookie[] c = hsr.getCookies(); - for (int i = 0; i < c.length; i++) { - if (c[i].getName().equals(localName)) { - return c[i].getValue(); - } - } - throw new UnresolvableException("$" + prefix + ":" + localName); - } else { - throw new UnresolvableException("$" + prefix + ":" + localName); - } - } - - /** - * Validate that the Object returned is not null. If it is - * null, throw an exception. - */ - private Object notNull(Object o, String prefix, String localName) - throws UnresolvableException { - if (o == null) { - throw new UnresolvableException("$" + (prefix == null ? "" : prefix + ":") + localName); - } - //p("resolved to: " + o); - return o; - } - } - - //********************************************************************* - // Support for XPath evaluation - - private PageContext pageContext; - private static HashMap exprCache; - private static JSTLPrefixResolver jstlPrefixResolver = null; - - /** - * Initialize globally useful data. - */ - private synchronized static void staticInit() { - if (jstlPrefixResolver == null) { - // register supported namespaces - jstlPrefixResolver = new JSTLPrefixResolver(); - jstlPrefixResolver.addNamespace("pageScope", PAGE_NS_URL); - jstlPrefixResolver.addNamespace("requestScope", REQUEST_NS_URL); - jstlPrefixResolver.addNamespace("sessionScope", SESSION_NS_URL); - jstlPrefixResolver.addNamespace("applicationScope", APP_NS_URL); - jstlPrefixResolver.addNamespace("param", PARAM_NS_URL); - jstlPrefixResolver.addNamespace("initParam", INITPARAM_NS_URL); - jstlPrefixResolver.addNamespace("header", HEADER_NS_URL); - jstlPrefixResolver.addNamespace("cookie", COOKIE_NS_URL); - - - // create a HashMap to cache the expressions - exprCache = new HashMap(); - } - } - - static DocumentBuilderFactory dbf = null; - static DocumentBuilder db = null; - static Document d = null; - - static Document getDummyDocument() { - try { - if (dbf == null) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - } - db = dbf.newDocumentBuilder(); - - DOMImplementation dim = db.getDOMImplementation(); - d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null); - //d = db.newDocument(); - return d; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - static Document getDummyDocumentWithoutRoot() { - try { - if (dbf == null) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - } - db = dbf.newDocumentBuilder(); - - d = db.newDocument(); - return d; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static Document getDocumentForNode(Node node) { - Document doc = getDummyDocumentWithoutRoot(); - Node importedNode = doc.importNode(node, true); - doc.appendChild(importedNode); - return doc; - } - - // The following variable is used for holding the modified xpath string - // when adapting parameter for Xalan XPath engine, where we need to have - // a Non null context node. - String modifiedXPath = null; - - - /** - * Evaluate an XPath expression to a String value. - */ - public String valueOf(Node n, String xpath) throws JspTagException { - //p("******** valueOf(" + n + ", " + xpath + ")"); - staticInit(); - // @@@ but where do we set the Pag4eContext for the varaiblecontext? - JstlVariableContext vs = new JstlVariableContext(); - XPathContext xpathSupport = new XPathContext(); - xpathSupport.setVarStack(vs); - - Vector varVector = fillVarStack(vs, xpathSupport); - - Node contextNode = adaptParamsForXalan(vs, n, xpath.trim()); - - xpath = modifiedXPath; - - //p("******** valueOf: modified xpath: " + xpath); - - XObject result = JSTLXPathAPI.eval(contextNode, xpath, - jstlPrefixResolver, xpathSupport, varVector); - - - //p("******Result TYPE => " + result.getTypeString() ); - - String resultString = result.str(); - //p("******** valueOf: after eval: " + resultString); - - return resultString; - - } - - /** - * Evaluate an XPath expression to a boolean value. - */ - public boolean booleanValueOf(Node n, String xpath) - throws JspTagException { - - staticInit(); - JstlVariableContext vs = new JstlVariableContext(); - XPathContext xpathSupport = new XPathContext(); - xpathSupport.setVarStack(vs); - - Vector varVector = fillVarStack(vs, xpathSupport); - - Node contextNode = adaptParamsForXalan(vs, n, xpath.trim()); - xpath = modifiedXPath; - - XObject result = JSTLXPathAPI.eval(contextNode, xpath, - jstlPrefixResolver, xpathSupport, varVector); - - try { - return result.bool(); - } catch (TransformerException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex); - } - } - - /** - * Evaluate an XPath expression to a List of nodes. - */ - public List selectNodes(Node n, String xpath) throws JspTagException { - - staticInit(); - JstlVariableContext vs = new JstlVariableContext(); - XPathContext xpathSupport = new XPathContext(); - xpathSupport.setVarStack(vs); - - Vector varVector = fillVarStack(vs, xpathSupport); - - Node contextNode = adaptParamsForXalan(vs, n, xpath.trim()); - xpath = modifiedXPath; - - XObject result = JSTLXPathAPI.eval(contextNode, xpath, - jstlPrefixResolver, xpathSupport, varVector); - try { - NodeList nl = JSTLXPathAPI.getNodeList(result); - return new JSTLNodeList(nl); - } catch (JspTagException e) { - try { - //If result can't be converted to NodeList we receive exception - // In this case we may have single primitive value as the result - // Populating List with this value ( String, Boolean or Number ) - - //System.out.println("JSTLXPathAPI.getNodeList thrown exception:"+ e); - Vector vector = new Vector(); - Object resultObject = null; - if (result.getType() == XObject.CLASS_BOOLEAN) { - resultObject = result.bool(); - } else if (result.getType() == XObject.CLASS_NUMBER) { - resultObject = result.num(); - } else if (result.getType() == XObject.CLASS_STRING) { - resultObject = result.str(); - } - - vector.add(resultObject); - return new JSTLNodeList(vector); - } catch (TransformerException te) { - throw new JspTagException(te.toString(), te); - } - } - - - } - - /** - * Evaluate an XPath expression to a single node. - */ - public Node selectSingleNode(Node n, String xpath) - throws JspTagException { - //p("selectSingleNode of XPathUtil = passed node:" + - // "xpath => " + n + " : " + xpath ); - - staticInit(); - JstlVariableContext vs = new JstlVariableContext(); - XPathContext xpathSupport = new XPathContext(); - xpathSupport.setVarStack(vs); - - Vector varVector = fillVarStack(vs, xpathSupport); - - Node contextNode = adaptParamsForXalan(vs, n, xpath.trim()); - xpath = modifiedXPath; - - return (Node) JSTLXPathAPI.selectSingleNode(contextNode, xpath, - jstlPrefixResolver, xpathSupport); - } - - /** - * Returns a locally appropriate context given a node. - */ - private VariableStack getLocalContext() { - // set up instance-specific contexts - VariableStack vc = new JstlVariableContext(); - return vc; - } - - //********************************************************************* - // Adapt XPath expression for integration with Xalan - - /** - * To evaluate an XPath expression using Xalan, we need - * to create an XPath object, which wraps an expression object and provides - * general services for execution of that expression. - *

An XPath object can be instantiated with the following information: - * - XPath expression to evaluate - * - SourceLocator - * (reports where an error occurred in the XML source or - * transformation instructions) - * - PrefixResolver - * (resolve prefixes to namespace URIs) - * - type - * (one of SELECT or MATCH) - * - ErrorListener - * (customized error handling) - *

Execution of the XPath expression represented by an XPath object - * is done via method execute which takes the following parameters: - * - XPathContext - * The execution context - * - Node contextNode - * The node that "." expresses - * - PrefixResolver namespaceContext - * The context in which namespaces in the XPath are supposed to be - * expanded. - *

Given all of this, if no context node is set for the evaluation - * of the XPath expression, one must be set so Xalan - * can successfully evaluate a JSTL XPath expression. - * (it will not work if the context node is given as a varialbe - * at the beginning of the expression) - * - * @@@ Provide more details... - */ - protected Node adaptParamsForXalan(JstlVariableContext jvc, Node n, - String xpath) { - Node boundDocument = null; - - modifiedXPath = xpath; - String origXPath = xpath; - boolean whetherOrigXPath = true; - - // If contextNode is not null then just pass the values to Xalan XPath - // unless this is an expression that starts off with an xml document - if (n != null && !xpath.startsWith("$")) { - return n; - } - - if (xpath.startsWith("$")) { - // JSTL uses $scopePrefix:varLocalName/xpath expression - - String varQName = xpath.substring(xpath.indexOf("$") + 1); - if (varQName.indexOf("/") > 0) { - varQName = varQName.substring(0, varQName.indexOf("/")); - } - String varPrefix = null; - String varLocalName = varQName; - if (varQName.indexOf(":") >= 0) { - varPrefix = varQName.substring(0, varQName.indexOf(":")); - varLocalName = varQName.substring(varQName.indexOf(":") + 1); - } - - if (xpath.indexOf("/") > 0) { - xpath = xpath.substring(xpath.indexOf("/")); - } else { - xpath = "/*"; - whetherOrigXPath = false; - } - - - try { - Object varObject = jvc.getVariableValue(null, varPrefix, - varLocalName); - //System.out.println( "varObject => : its Class " +varObject + - // ":" + varObject.getClass() ); - - if (Class.forName("org.w3c.dom.Document").isInstance( - varObject)) { - //boundDocument = ((Document)varObject).getDocumentElement(); - boundDocument = ((Document) varObject); - } else { - - //System.out.println("Creating a Dummy document to pass " + - // " onto as context node " ); - - if (Class.forName("org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(varObject)) { - Document newDocument = getDummyDocument(); - - JSTLNodeList jstlNodeList = (JSTLNodeList) varObject; - if (jstlNodeList.getLength() == 1) { - if (Class.forName("org.w3c.dom.Node").isInstance( - jstlNodeList.elementAt(0))) { - Node node = (Node) jstlNodeList.elementAt(0); - boundDocument = getDocumentForNode(node); - if (whetherOrigXPath) { - xpath = "/*" + xpath; - } - - } else { - - //Nodelist with primitive type - Object myObject = jstlNodeList.elementAt(0); - - //p("Single Element of primitive type"); - //p("Type => " + myObject.getClass()); - - xpath = myObject.toString(); - - //p("String value ( xpathwould be this) => " + xpath); - boundDocument = newDocument; - } - - } else { - - Element dummyroot = newDocument.getDocumentElement(); - for (int i = 0; i < jstlNodeList.getLength(); i++) { - Node currNode = (Node) jstlNodeList.item(i); - - Node importedNode = newDocument.importNode( - currNode, true); - - //printDetails ( newDocument); - - dummyroot.appendChild(importedNode); - - //p( "Details of the document After importing"); - //printDetails ( newDocument); - } - boundDocument = newDocument; - // printDetails ( boundDocument ); - //Verify :As we are adding Document element we need - // to change the xpath expression.Hopefully this - // won't change the result - - xpath = "/*" + xpath; - } - } else if (Class.forName("org.w3c.dom.Node").isInstance( - varObject)) { - boundDocument = getDocumentForNode((Node) varObject); - if (whetherOrigXPath) { - xpath = "/*" + xpath; - } - } else { - boundDocument = getDummyDocument(); - xpath = origXPath; - } - - - } - } catch (UnresolvableException ue) { - // TODO: LOG - System.out.println("Variable Unresolvable :" + ue.getMessage()); - ue.printStackTrace(); - } catch (ClassNotFoundException cnf) { - // Will never happen - } - } else { - //System.out.println("Not encountered $ Creating a Dummydocument 2 "+ - // "pass onto as context node " ); - boundDocument = getDummyDocument(); - } - - modifiedXPath = xpath; - //System.out.println("Modified XPath::boundDocument =>" + modifiedXPath + - // "::" + boundDocument ); - - return boundDocument; - } - - - //********************************************************************* - // - - /** - * * @@@ why do we have to pass varVector in the varStack first, and then - * to XPath object? - */ - private Vector fillVarStack(JstlVariableContext vs, XPathContext xpathSupport) - throws JspTagException { - org.apache.xpath.VariableStack myvs = xpathSupport.getVarStack(); - Vector varVector = getVariableQNames(); - for (int i = 0; i < varVector.size(); i++) { - - QName varQName = (QName) varVector.elementAt(i); - - try { - XObject variableValue = vs.getVariableOrParam(xpathSupport, varQName); - //p("&&&&Variable set to => " + variableValue.toString() ); - //p("&&&&Variable type => " + variableValue.getTypeString() ); - myvs.setGlobalVariable(i, variableValue); - - } catch (TransformerException te) { - throw new JspTagException(te.toString(), te); - } - - } - return varVector; - } - - - //********************************************************************* - // Static support for context retrieval from parent tag - - public static Node getContext(Tag t) throws JspTagException { - ForEachTag xt = - (ForEachTag) TagSupport.findAncestorWithClass( - t, ForEachTag.class); - if (xt == null) { - return null; - } else { - return (xt.getContext()); - } - } - - //********************************************************************* - // Utility methods - - private static void p(String s) { - System.out.println("[XPathUtil] " + s); - } - - public static void printDetails(Node n) { - System.out.println("\n\nDetails of Node = > " + n); - System.out.println("Name:Type:Node Value = > " + n.getNodeName() + - ":" + n.getNodeType() + ":" + n.getNodeValue()); - System.out.println("Namespace URI : Prefix : localName = > " + - n.getNamespaceURI() + ":" + n.getPrefix() + ":" + n.getLocalName()); - System.out.println("\n Node has children => " + n.hasChildNodes()); - if (n.hasChildNodes()) { - NodeList nl = n.getChildNodes(); - System.out.println("Number of Children => " + nl.getLength()); - for (int i = 0; i < nl.getLength(); i++) { - Node childNode = nl.item(i); - printDetails(childNode); - } - } - } -} - -class JSTLNodeList extends Vector implements NodeList { - - Vector nodeVector; - - public JSTLNodeList(Vector nodeVector) { - this.nodeVector = nodeVector; - } - - public JSTLNodeList(NodeList nl) { - nodeVector = new Vector(); - //System.out.println("[JSTLNodeList] nodelist details"); - for (int i = 0; i < nl.getLength(); i++) { - Node currNode = nl.item(i); - //XPathUtil.printDetails ( currNode ); - nodeVector.add(i, nl.item(i)); - } - } - - public JSTLNodeList(Node n) { - nodeVector = new Vector(); - nodeVector.addElement(n); - } - - - public Node item(int index) { - return (Node) nodeVector.elementAt(index); - } - - @Override - public Object elementAt(int index) { - return nodeVector.elementAt(index); - } - - @Override - public Object get(int index) { - return nodeVector.get(index); - } - - public int getLength() { - return nodeVector.size(); - } - - @Override - public int size() { - //System.out.println("JSTL node list size => " + nodeVector.size() ); - return nodeVector.size(); - } - - // Can implement other Vector methods to redirect those methods to - // the vector in the variable param. As we are not using them as part - // of this implementation we are not doing that here. If this changes - // then we need to override those methods accordingly - -} - - - - Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java (working copy) @@ -17,12 +17,15 @@ package org.apache.taglibs.standard.tag.common.xml; -import java.util.List; - import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.LoopTagSupport; +import javax.servlet.jsp.tagext.Tag; +import javax.servlet.jsp.tagext.TagSupport; -import org.apache.taglibs.standard.resources.Resources; +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; /** *

Support for the XML library's <forEach> tag.

@@ -32,60 +35,44 @@ */ public class ForEachTag extends LoopTagSupport { - //********************************************************************* - // Private state + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + private JSTLXPathContext context; - private String select; // tag attribute - private List nodes; // XPath result - private int nodesIndex; // current index - private org.w3c.dom.Node current; // current node + public ForEachTag() { + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); + } - //********************************************************************* - // Iteration control methods + @Override + public void release() { + super.release(); + compiler = null; + select = null; + context = null; + } - // (We inherit semantics and Javadoc from LoopTagSupport.) - @Override protected void prepare() throws JspTagException { - nodesIndex = 0; - XPathUtil xu = new XPathUtil(pageContext); - nodes = xu.selectNodes(XPathUtil.getContext(this), select); + context = select.iterate(getContext(this), pageContext); } @Override protected boolean hasNext() throws JspTagException { - return (nodesIndex < nodes.size()); + return context.hasNext(); } @Override protected Object next() throws JspTagException { - Object o = nodes.get(nodesIndex++); - if (!(o instanceof org.w3c.dom.Node)) { - throw new JspTagException( - Resources.getMessage("FOREACH_NOT_NODESET")); - } - current = (org.w3c.dom.Node) o; - return current; + return context.next(); } //********************************************************************* - // Tag logic and lifecycle management - - // Releases any resources we may have (or inherit) - - @Override - public void release() { - init(); - super.release(); - } - - - //********************************************************************* // Attribute accessors public void setSelect(String select) { - this.select = select; + this.select = compiler.compile(select); } public void setBegin(int begin) throws JspTagException { @@ -111,20 +98,13 @@ /* Retrieves the current context. */ - public org.w3c.dom.Node getContext() throws JspTagException { - // expose the current node as the context - return current; + public static JSTLXPathContext getContext(Tag child) { + ForEachTag forEachTag = (ForEachTag) TagSupport.findAncestorWithClass(child, ForEachTag.class); + if (forEachTag == null) { + return null; + } else { + return forEachTag.context; + } } - - - //********************************************************************* - // Private utility methods - - private void init() { - select = null; - nodes = null; - nodesIndex = 0; - current = null; - } } Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java (working copy) @@ -17,13 +17,14 @@ package org.apache.taglibs.standard.tag.common.xml; -import java.util.List; - import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.TagSupport; import org.apache.taglibs.standard.tag.common.core.Util; +import org.apache.taglibs.standard.xpath.JSTLXPathCompiler; +import org.apache.taglibs.standard.xpath.JSTLXPathExpression; +import org.apache.taglibs.standard.xpath.JSTLXPathFactory; /** *

Tag handler for <set> in JSTL's XML library.

@@ -32,13 +33,11 @@ */ public class SetTag extends TagSupport { - //********************************************************************* - // Internal state + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + private String var; + private int scope = PageContext.PAGE_SCOPE; - private String select; // tag attribute - private String var; // tag attribute - private int scope; // processed tag attribute - //********************************************************************* // Construction and initialization @@ -48,19 +47,18 @@ * superclass constructor. */ public SetTag() { - super(); - init(); + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); } - // resets local state - - private void init() { - var = null; + @Override + public void release() { + super.release(); + compiler = null; select = null; - scope = PageContext.PAGE_SCOPE; + var = null; } - //********************************************************************* // Tag logic @@ -68,40 +66,16 @@ @Override public int doStartTag() throws JspException { - // process the query - XPathUtil xu = new XPathUtil(pageContext); - List result = - xu.selectNodes(XPathUtil.getContext(this), select); - Object ret = result; - - // unwrap primitive types if that's what we received - if (result.size() == 1) { - Object o = result.get(0); - if (o instanceof String || o instanceof Boolean - || o instanceof Number) { - ret = o; - } - } - - // expose the final result - pageContext.setAttribute(var, ret, scope); + Object result = select.evaluateObject(ForEachTag.getContext(this), pageContext); + pageContext.setAttribute(var, result, scope); return SKIP_BODY; } - // Releases any resources we may have (or inherit) - - @Override - public void release() { - super.release(); - init(); - } - - //********************************************************************* // Attribute accessors public void setSelect(String select) { - this.select = select; + this.select = compiler.compile(select); } public void setVar(String var) { Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java (working copy) @@ -20,6 +20,10 @@ import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.ConditionalTagSupport; +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.

* @@ -28,55 +32,27 @@ public class IfTag extends ConditionalTagSupport { - //********************************************************************* - // Constructor and lifecycle management + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; - // initialize inherited and local state - public IfTag() { - super(); - init(); + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); } - // Releases any resources we may have (or inherit) - @Override public void release() { super.release(); - init(); + compiler = null; + select = null; } - - //********************************************************************* - // Supplied conditional logic - @Override protected boolean condition() throws JspTagException { - XPathUtil xu = new XPathUtil(pageContext); - return (xu.booleanValueOf(XPathUtil.getContext(this), select)); + return select.evaluateBoolean(ForEachTag.getContext(this), pageContext); } - - //********************************************************************* - // Private state - - private String select; // the value of the 'test' attribute - - - //********************************************************************* - // Attribute accessors - public void setSelect(String select) { - this.select = select; + this.select = compiler.compile(select); } - - - //********************************************************************* - // Private utility methods - - // resets internal state - - private void init() { - select = null; - } } Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java (working copy) @@ -5,9 +5,9 @@ * 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. @@ -22,52 +22,42 @@ import javax.servlet.jsp.tagext.TagSupport; import org.apache.taglibs.standard.util.EscapeXML; +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 { - //********************************************************************* - // Internal state + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; + protected boolean escapeXml = true; // tag attribute - private String select; // tag attribute - protected boolean escapeXml; // tag attribute - - //********************************************************************* - // Construction and initialization - - /** - * Constructs a new handler. As with TagSupport, subclasses should - * not provide other constructors and are expected to call the - * superclass constructor. - */ public ExprSupport() { - super(); - init(); + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); } - // resets local state - - private void init() { + @Override + public void release() { + super.release(); + compiler = null; select = null; - escapeXml = true; } - //********************************************************************* // Tag logic // applies XPath expression from 'select' and prints the result - @Override public int doStartTag() throws JspException { try { - XPathUtil xu = new XPathUtil(pageContext); - String result = xu.valueOf(XPathUtil.getContext(this), select); + String result = select.evaluateString(ForEachTag.getContext(this), pageContext); EscapeXML.emit(result, escapeXml, pageContext.getOut()); return SKIP_BODY; } catch (java.io.IOException ex) { @@ -75,19 +65,7 @@ } } - // Releases any resources we may have (or inherit) - - @Override - public void release() { - super.release(); - init(); - } - - - //********************************************************************* - // Attribute accessors - public void setSelect(String select) { - this.select = select; + this.select = compiler.compile(select); } } Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java (working copy) @@ -1,296 +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 java.util.Vector; - -import javax.servlet.jsp.JspTagException; -import javax.xml.transform.TransformerException; - -import org.apache.taglibs.standard.resources.Resources; -import org.apache.xml.utils.PrefixResolver; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathAPI; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XObject; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.traversal.NodeIterator; - -/** - * The methods in this class are convenience methods into the - * low-level XPath API. - * These functions tend to be a little slow, since a number of objects must be - * created for each evaluation. A faster way is to precompile the - * XPaths using the low-level API, and then just use the XPaths - * over and over. - *

NOTE: In particular, each call to this method will create a new - * XPathContext, a new DTMManager... and thus a new DTM. That's very - * safe, since it guarantees that you're always processing against a - * fully up-to-date view of your document. But it's also portentially - * very expensive, since you're rebuilding the DTM every time. You should - * consider using an instance of CachedXPathAPI rather than these static - * methods. - * - * @see XPath Specification - */ -public class JSTLXPathAPI extends XPathAPI { - /** - * Use an XPath string to select a single node. - * XPath namespace prefixes are resolved using the prefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return The first node found that matches the XPath, or null. - * @throws JspTagException - */ - public static Node selectSingleNode( - Node contextNode, String str, PrefixResolver prefixResolver) - throws JspTagException { - - // Have the XObject return its result as a NodeSetDTM. - NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver); - - // Return the first node, or null - return nl.nextNode(); - } - - /** - * Use an XPath string to select a single node. - * XPath namespace prefixes are resolved using the prefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return The first node found that matches the XPath, or null. - * @throws JspTagException - */ - public static Node selectSingleNode( - Node contextNode, String str, PrefixResolver prefixResolver, - XPathContext xpathSupport) throws JspTagException { - - // Have the XObject return its result as a NodeSetDTM. - NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver, xpathSupport); - - // Return the first node, or null - return nl.nextNode(); - } - - /** - * Use an XPath string to select a nodelist. - * XPath namespace prefixes are resolved using PrefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return A NodeIterator, should never be null. - * @throws JspTagException - */ - public static NodeIterator selectNodeIterator( - Node contextNode, String str, PrefixResolver prefixResolver) - throws JspTagException { - - // Execute the XPath, and have it return the result - XObject list = eval(contextNode, str, prefixResolver, null); - - // Have the XObject return its result as a NodeSetDTM. - return getNodeIterator(list); - } - - /** - * Use an XPath string to select a nodelist. - * XPath namespace prefixes are resolved using PrefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return A NodeIterator, should never be null. - * @throws JspTagException - */ - public static NodeIterator selectNodeIterator( - Node contextNode, String str, PrefixResolver prefixResolver, - XPathContext xpathSupport) throws JspTagException { - - // Execute the XPath, and have it return the result - XObject list = eval(contextNode, str, prefixResolver, xpathSupport); - - // Have the XObject return its result as a NodeSetDTM. - return getNodeIterator(list); - } - - /** - * Use an XPath string to select a nodelist. - * XPath namespace prefixes are resolved using the prefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return A NodeIterator, should never be null. - * @throws JspTagException - */ - private static NodeList selectNodeList( - Node contextNode, String str, PrefixResolver prefixResolver) - throws JspTagException { - // Execute the XPath, and have it return the result - XObject list = eval(contextNode, str, prefixResolver, null); - - // Return a NodeList. - return getNodeList(list); - } - - /** - * Use an XPath string to select a nodelist. - * XPath namespace prefixes are resolved using the prefixResolver. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces. - * @return A NodeIterator, should never be null. - * @throws JspTagException - */ - public static NodeList selectNodeList( - Node contextNode, String str, PrefixResolver prefixResolver, - XPathContext xpathSupport) - throws JspTagException { - // Execute the XPath, and have it return the result - XObject list = eval(contextNode, str, prefixResolver, xpathSupport); - - // Return a NodeList. - return getNodeList(list); - } - - /** - * Returns a NodeIterator from an XObject. - * - * @param list The XObject from which a NodeIterator is returned. - * @return A NodeIterator, should never be null. - * @throws JspTagException - */ - private static NodeIterator getNodeIterator(XObject list) - throws JspTagException { - try { - return list.nodeset(); - } catch (TransformerException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex); - } - } - - /** - * Returns a NodeList from an XObject. - * - * @param list The XObject from which a NodeList is returned. - * @return A NodeList, should never be null. - * @throws JspTagException - */ - static NodeList getNodeList(XObject list) - throws JspTagException { - try { - return list.nodelist(); - } catch (TransformerException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex); - } - } - - /** - * Evaluate XPath string to an XObject. - * XPath namespace prefixes are resolved from the namespaceNode. - * The implementation of this is a little slow, since it creates - * a number of objects each time it is called. This could be optimized - * to keep the same objects around, but then thread-safety issues would arise. - * - * @param contextNode The node to start searching from. - * @param str A valid XPath string. - * @param xpathSupport The node from which prefixes in the XPath will be resolved to namespaces. - * @param prefixResolver Will be called if the parser encounters namespace - * prefixes, to resolve the prefixes to URLs. - * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. - * @throws JspTagException - * @see org.apache.xpath.objects.XObject - * @see org.apache.xpath.objects.XNull - * @see org.apache.xpath.objects.XBoolean - * @see org.apache.xpath.objects.XNumber - * @see org.apache.xpath.objects.XString - * @see org.apache.xpath.objects.XRTreeFrag - */ - public static XObject eval( - Node contextNode, String str, PrefixResolver prefixResolver, - XPathContext xpathSupport) throws JspTagException { - //System.out.println("eval of XPathContext params: contextNode:str(xpath)"+ - // ":prefixResolver:xpathSupport => " + contextNode + ":" + str + ":" + - // prefixResolver + ":" + xpathSupport ); - try { - if (xpathSupport == null) { - return eval(contextNode, str, prefixResolver); - } - - // Since we don't have a XML Parser involved here, install some default support - // for things like namespaces, etc. - // (Changed from: XPathContext xpathSupport = new XPathContext(); - // because XPathContext is weak in a number of areas... perhaps - // XPathContext should be done away with.) - // Create the XPath object. - XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null); - - // Execute the XPath, and have it return the result - int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode); - - // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode ); - XObject xobj = xpath.execute(xpathSupport, ctxtNode, prefixResolver); - return xobj; - } catch (TransformerException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex); - } catch (IllegalArgumentException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex); - } - } - - public static XObject eval( - Node contextNode, String str, PrefixResolver prefixResolver, - XPathContext xpathSupport, Vector varQNames) throws JspTagException { - //p("***************** eval "); - //p( "contextNode => " + contextNode ); - //p( "XPath str => " + str ); - //p( "PrefixResolver => " + prefixResolver ); - //p( "XPath Context => " + xpathSupport ); - //p( "Var QNames => " + varQNames ); - //p( "Global Var Size => " + varQNames.size() ); - try { - XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null); - xpath.fixupVariables(varQNames, varQNames.size()); - // Execute the XPath, and have it return the result - int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode); - // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode ); - return xpath.execute(xpathSupport, ctxtNode, prefixResolver); - } catch (TransformerException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex); - } catch (IllegalArgumentException ex) { - throw new JspTagException( - Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex); - } - } - - private static void p(String s) { - System.out.println("[JSTLXPathAPI] " + s); - } -} Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java (working copy) @@ -1,145 +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 java.util.HashMap; - -import org.apache.xml.utils.PrefixResolver; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -/** - * - * This class implements a JSTL PrefixResolver that - * can be used to perform prefix-to-namespace lookup - * for the XPath object. - */ -public class JSTLPrefixResolver implements PrefixResolver { - - /** - * The context to resolve the prefix from, if the context - * is not given. - */ - - HashMap namespaces; - - /** - * The URI for the XML namespace. - * (Duplicate of that found in org.apache.xpath.XPathContext). - */ - - public static final String S_XMLNAMESPACEURI = - "http://www.w3.org/XML/1998/namespace"; - - /** - * No-arg constructor which would create empty HashMap of namespaces - */ - public JSTLPrefixResolver() { - namespaces = new HashMap(); - } - - public JSTLPrefixResolver(HashMap nses) { - namespaces = nses; - } - - /** - * Given a namespace, get the corresponding prefix. This assumes that - * the PrevixResolver hold's it's own namespace context, or is a namespace - * context itself. - * - * @param prefix Prefix to resolve. - * @return Namespace that prefix resolves to, or null if prefix - * is not bound. - */ - public String getNamespaceForPrefix(String prefix) { - return (String) namespaces.get(prefix); - } - - /** - * Given a prefix and a Context Node, get the corresponding namespace. - * Warning: This will not work correctly if namespaceContext - * is an attribute node. - * - * @param prefix Prefix to resolve. - * @param namespaceContext Node from which to start searching for a - * xmlns attribute that binds a prefix to a namespace. - * @return Namespace that prefix resolves to, or null if prefix - * is not bound. - */ - public String getNamespaceForPrefix(String prefix, - org.w3c.dom.Node namespaceContext) { - - Node parent = namespaceContext; - String namespace = null; - - if (prefix.equals("xml")) { - namespace = S_XMLNAMESPACEURI; - } else { - int type; - - while ((null != parent) && (null == namespace) - && (((type = parent.getNodeType()) == Node.ELEMENT_NODE) - || (type == Node.ENTITY_REFERENCE_NODE))) { - if (type == Node.ELEMENT_NODE) { - NamedNodeMap nnm = parent.getAttributes(); - - for (int i = 0; i < nnm.getLength(); i++) { - Node attr = nnm.item(i); - String aname = attr.getNodeName(); - boolean isPrefix = aname.startsWith("xmlns:"); - - if (isPrefix || aname.equals("xmlns")) { - int index = aname.indexOf(':'); - String p = isPrefix ? aname.substring(index + 1) : ""; - - if (p.equals(prefix)) { - namespace = attr.getNodeValue(); - - break; - } - } - } - } - - parent = parent.getParentNode(); - } - } - - return namespace; - } - - /** - * Return the base identifier. - * - * @return null - */ - public String getBaseIdentifier() { - return null; - } - - /** - * @see PrefixResolver#handlesNullPrefixes() - */ - public boolean handlesNullPrefixes() { - return false; - } - - public void addNamespace(String prefix, String uri) { - namespaces.put(prefix, uri); - } - -} Index: impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java =================================================================== --- impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java (revision 1050272) +++ impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java (working copy) @@ -20,6 +20,9 @@ import javax.servlet.jsp.JspTagException; import org.apache.taglibs.standard.tag.common.core.WhenTagSupport; +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.

@@ -29,54 +32,27 @@ public class WhenTag extends WhenTagSupport { - //********************************************************************* - // Constructor and lifecycle management + private JSTLXPathCompiler compiler; + private JSTLXPathExpression select; - // initialize inherited and local state - public WhenTag() { - super(); - init(); + JSTLXPathFactory xpf = JSTLXPathFactory.getFactory(); + compiler = xpf.newCompiler(); } - // Releases any resources we may have (or inherit) - @Override public void release() { super.release(); - init(); + compiler = null; + select = null; } - - //********************************************************************* - // Supplied conditional logic - @Override protected boolean condition() throws JspTagException { - XPathUtil xu = new XPathUtil(pageContext); - return (xu.booleanValueOf(XPathUtil.getContext(this), select)); + return select.evaluateBoolean(ForEachTag.getContext(this), pageContext); } - //********************************************************************* - // Private state - - private String select; // the value of the 'test' attribute - - - //********************************************************************* - // Attribute accessors - public void setSelect(String select) { - this.select = select; + this.select = compiler.compile(select); } - - - //********************************************************************* - // Private utility methods - - // resets internal state - - private void init() { - select = null; - } }