View | Details | Raw Unified | Return to bug 27717
Collapse All | Expand All

(-)impl/src/test/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpressionTest.java (+94 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.jaxp;
18
19
import java.io.InputStream;
20
21
import javax.servlet.jsp.JspTagException;
22
import javax.servlet.jsp.PageContext;
23
import javax.xml.parsers.DocumentBuilder;
24
import javax.xml.parsers.DocumentBuilderFactory;
25
import javax.xml.xpath.XPath;
26
import javax.xml.xpath.XPathExpression;
27
import javax.xml.xpath.XPathExpressionException;
28
import javax.xml.xpath.XPathFactory;
29
30
import org.apache.taglibs.standard.xpath.JSTLVariableResolver;
31
import org.apache.taglibs.standard.xpath.xalan.XalanXPathExpressionTest;
32
import org.junit.Assert;
33
import org.junit.Before;
34
import org.junit.BeforeClass;
35
import org.junit.Ignore;
36
import org.junit.Test;
37
import org.w3c.dom.Document;
38
39
import static org.easymock.EasyMock.createMock;
40
import static org.easymock.EasyMock.expect;
41
import static org.easymock.EasyMock.replay;
42
import static org.easymock.EasyMock.verify;
43
44
/**
45
 */
46
public class JAXPXPathExpressionTest {
47
48
    private XPath xpath;
49
    private JSTLVariableResolver resolver;
50
    private PageContext pageContext;
51
52
    private static Document d;
53
54
    @BeforeClass
55
    public static void loadTestXML() throws Exception {
56
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
57
        dbf.setNamespaceAware(true);
58
        dbf.setValidating(false);
59
        DocumentBuilder db = dbf.newDocumentBuilder();
60
        InputStream is = XalanXPathExpressionTest.class.getResourceAsStream("test.xml");
61
        try {
62
            d = db.parse(is);
63
        } finally {
64
            is.close();
65
        }
66
    }
67
68
    @Before
69
    public void setup() {
70
        XPathFactory factory = XPathFactory.newInstance();
71
        xpath = factory.newXPath();
72
        resolver = new JSTLVariableResolver();
73
        xpath.setXPathVariableResolver(resolver);
74
        pageContext = createMock(PageContext.class);
75
76
    }
77
78
    @Ignore
79
    @Test
80
    public void testBooleanExpressionReturnsBoolean() throws JspTagException, XPathExpressionException {
81
        XPathExpression exp = xpath.compile("true()");
82
        JAXPXPathExpression xpe = new JAXPXPathExpression(exp, resolver);
83
        Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, null));
84
    }
85
    @Test
86
    public void testSelectTextFromDOM() throws Exception {
87
        XPathExpression exp = xpath.compile("string($a/root/b/hello)");
88
        JAXPXPathExpression xpe = new JAXPXPathExpression(exp, resolver);
89
        expect(pageContext.findAttribute("a")).andReturn(d);
90
        replay(pageContext);
91
        Assert.assertEquals("world", xpe.evaluateString(null, pageContext));
92
        verify(pageContext);
93
    }
94
}
(-)impl/src/test/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpressionTest.java (+169 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import java.io.InputStream;
20
import java.util.concurrent.Callable;
21
22
import javax.servlet.jsp.PageContext;
23
import javax.xml.parsers.DocumentBuilder;
24
import javax.xml.parsers.DocumentBuilderFactory;
25
26
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
27
import org.apache.xpath.XPath;
28
import org.junit.Assert;
29
import org.junit.Before;
30
import org.junit.BeforeClass;
31
import org.junit.Ignore;
32
import org.junit.Test;
33
import org.w3c.dom.Document;
34
import org.w3c.dom.Element;
35
36
import static org.easymock.EasyMock.createMock;
37
import static org.easymock.EasyMock.expect;
38
import static org.easymock.EasyMock.replay;
39
import static org.easymock.EasyMock.verify;
40
41
/**
42
 */
43
public class XalanXPathExpressionTest {
44
    private PageContext pageContext;
45
    private static Document d;
46
    private static DocumentBuilder db;
47
48
    @BeforeClass
49
    public static void loadTestXML() throws Exception {
50
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
51
        dbf.setNamespaceAware(true);
52
        dbf.setValidating(false);
53
        db = dbf.newDocumentBuilder();
54
        InputStream is = XalanXPathExpressionTest.class.getResourceAsStream("test.xml");
55
        try {
56
            d = db.parse(is);
57
        } finally {
58
            is.close();
59
        }
60
    }
61
62
    @Before
63
    public void setup() {
64
        pageContext = createMock(PageContext.class);
65
    }
66
67
    @Test
68
    public void testBooleanExpressionReturnsBoolean() throws Exception {
69
        XPath xpath = new XPath("true()", null, null, XPath.SELECT);
70
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
71
        Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, null));
72
    }
73
74
    @Test
75
    public void testStringExpressionReturnsString() throws Exception {
76
        XPath xpath = new XPath("\"hello\"", null, null, XPath.SELECT);
77
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
78
        Assert.assertEquals("hello", xpe.evaluateObject(null, null));
79
    }
80
81
    @Test
82
    public void testNumberExpressionReturnsNumber() throws Exception {
83
        XPath xpath = new XPath("1234", null, null, XPath.SELECT);
84
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
85
        Assert.assertEquals(1234.0, xpe.evaluateObject(null, null));
86
    }
87
88
    @Test
89
    public void testBooleanVariable() throws Exception {
90
        XPath xpath = new XPath("$a", null, null, XPath.SELECT);
91
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
92
        expect(pageContext.findAttribute("a")).andReturn(Boolean.TRUE);
93
        replay(pageContext);
94
        Assert.assertEquals(Boolean.TRUE, xpe.evaluateObject(null, pageContext));
95
        verify(pageContext);
96
    }
97
98
    @Test
99
    public void testNumberVariable() throws Exception {
100
        XPath xpath = new XPath("$a", null, null, XPath.SELECT);
101
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
102
        Number value = 1234.5;
103
        expect(pageContext.findAttribute("a")).andReturn(value);
104
        replay(pageContext);
105
        Assert.assertEquals(value, xpe.evaluateObject(null, pageContext));
106
        verify(pageContext);
107
    }
108
109
    @Test
110
    public void testStringVariable() throws Exception {
111
        XPath xpath = new XPath("$a", null, null, XPath.SELECT);
112
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
113
        String value = "Hello";
114
        expect(pageContext.findAttribute("a")).andReturn(value);
115
        replay(pageContext);
116
        Assert.assertEquals(value, xpe.evaluateObject(null, pageContext));
117
        verify(pageContext);
118
    }
119
120
    @Test
121
    public void testSelectTextFromDOM() throws Exception {
122
        XPath xpath = new XPath("string($a/root/b/hello)", null, null, XPath.SELECT);
123
        XalanXPathExpression xpe = new XalanXPathExpression(xpath);
124
        expect(pageContext.findAttribute("a")).andReturn(d);
125
        replay(pageContext);
126
        Assert.assertEquals("world", xpe.evaluateObject(null, pageContext));
127
        verify(pageContext);
128
    }
129
130
    @Ignore
131
    @Test
132
    public void testIterationPerformance() throws Exception {
133
        int size = 200000;
134
        System.out.println("Creating DOM");
135
        d = db.newDocument();
136
        Element root = d.createElement("root");
137
        d.appendChild(root);
138
        for (int i = 0; i < size; i++) {
139
            Element a = d.createElement("a");
140
            root.appendChild(a);
141
            Element b = d.createElement("b");
142
            b.setTextContent(Integer.toString(i));
143
            a.appendChild(b);
144
        }
145
        System.out.println("DOM created");
146
        expect(pageContext.findAttribute("doc")).andStubReturn(d);
147
        replay(pageContext);
148
        final XalanXPathExpression forEach = new XalanXPathExpression(new XPath("$doc/root/a", null, null, XPath.SELECT));
149
        final XalanXPathExpression inner = new XalanXPathExpression(new XPath("b", null, null, XPath.SELECT));
150
        Callable<Long> test = new Callable<Long>() {
151
            public Long call() throws Exception {
152
                long time = -System.nanoTime();
153
                JSTLXPathContext iterator = forEach.iterate(null, pageContext);
154
                while (iterator.hasNext()) {
155
                    Object node = iterator.next();
156
                    String s = inner.evaluateString(iterator, pageContext);
157
                }
158
                time += System.nanoTime();
159
                return time;
160
            }
161
        };
162
        // warm up the JIT
163
        test.call();
164
        System.out.println("JIT Primed, starting test");
165
        long time = test.call();
166
        System.out.println("time = " + time/1000000+"ms.");
167
        System.out.flush();
168
    }
169
}
(-)impl/src/test/resources/org/apache/taglibs/standard/xpath/xalan/test.xml (+10 lines)
Line 0 Link Here
1
<root>
2
    <a>
3
        <num>one</num>
4
        <num>two</num>
5
        <num>three</num>
6
    </a>
7
    <b>
8
        <hello>world</hello>
9
    </b>
10
</root>
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathExpression.java (+33 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.PageContext;
21
22
/**
23
 */
24
public interface JSTLXPathExpression {
25
26
    boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException;
27
28
    String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException;
29
30
    Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException;
31
32
    JSTLXPathContext iterate(JSTLXPathContext context, PageContext pageContext) throws JspTagException;
33
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathFactory.java (+42 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.jaxp;
18
19
import javax.xml.xpath.XPath;
20
import javax.xml.xpath.XPathFactory;
21
22
import org.apache.taglibs.standard.xpath.JSTLVariableResolver;
23
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
24
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
25
26
/**
27
 */
28
public class JAXPXPathFactory extends JSTLXPathFactory {
29
    private static final XPathFactory xpf = XPathFactory.newInstance();
30
31
    @Override
32
    public JSTLXPathCompiler newCompiler() {
33
        XPath xpath;
34
        synchronized (xpf) {
35
            xpath = xpf.newXPath();
36
        }
37
        JSTLVariableResolver resolver = new JSTLVariableResolver();
38
        xpath.setXPathVariableResolver(resolver);
39
        xpath.setNamespaceContext(resolver);
40
        return new JAXPXPathCompiler(xpath);
41
    }
42
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathCompiler.java (+44 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.jaxp;
18
19
import javax.xml.xpath.XPath;
20
import javax.xml.xpath.XPathExpressionException;
21
22
import org.apache.taglibs.standard.xpath.InvalidXPathException;
23
import org.apache.taglibs.standard.xpath.JSTLVariableResolver;
24
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
25
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
26
27
/**
28
 */
29
public class JAXPXPathCompiler implements JSTLXPathCompiler {
30
    private final XPath xpath;
31
32
    public JAXPXPathCompiler(XPath xpath) {
33
        this.xpath = xpath;
34
    }
35
36
    public JSTLXPathExpression compile(String select) {
37
        try {
38
            JSTLVariableResolver resolver = (JSTLVariableResolver) xpath.getXPathVariableResolver();
39
            return new JAXPXPathExpression(xpath.compile(select), resolver);
40
        } catch (XPathExpressionException e) {
41
            throw new InvalidXPathException(e);
42
        }
43
    }
44
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathExpression.java (+69 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.jaxp;
18
19
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.PageContext;
21
import javax.xml.namespace.QName;
22
import javax.xml.xpath.XPathConstants;
23
import javax.xml.xpath.XPathExpression;
24
import javax.xml.xpath.XPathExpressionException;
25
26
import org.apache.taglibs.standard.xpath.JSTLVariableResolver;
27
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
28
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
29
import org.w3c.dom.Node;
30
import org.w3c.dom.NodeList;
31
32
/**
33
 */
34
public class JAXPXPathExpression implements JSTLXPathExpression {
35
    private final XPathExpression expr;
36
    private final JSTLVariableResolver resolver;
37
38
    public JAXPXPathExpression(XPathExpression expr, JSTLVariableResolver resolver) {
39
        this.expr = expr;
40
        this.resolver = resolver;
41
    }
42
43
    public boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
44
        return (Boolean) evaluate(context, pageContext, XPathConstants.BOOLEAN);
45
    }
46
47
    public String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
48
        return (String) evaluate(context, pageContext, XPathConstants.STRING);
49
    }
50
51
    public Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
52
        return evaluate(context, pageContext, XPathConstants.NODE);
53
    }
54
55
    public JSTLXPathContext iterate(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
56
        NodeList nodes = (NodeList) evaluate(context, pageContext, XPathConstants.NODESET);
57
        return new JAXPXPathContext(nodes);
58
    }
59
60
    private Object evaluate(JSTLXPathContext context, PageContext pageContext, QName resultType) throws JspTagException {
61
        resolver.setPageContext(pageContext);
62
        Node contextNode = (context == null) ? null : ((JAXPXPathContext) context).current();
63
        try {
64
            return expr.evaluate(contextNode, resultType);
65
        } catch (XPathExpressionException e) {
66
            throw new JspTagException(e);
67
        }
68
    }
69
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/jaxp/JAXPXPathContext.java (+44 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.jaxp;
18
19
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
20
import org.w3c.dom.Node;
21
import org.w3c.dom.NodeList;
22
23
/**
24
 */
25
public class JAXPXPathContext implements JSTLXPathContext {
26
    private final NodeList nodes;
27
    private int index;
28
29
    public JAXPXPathContext(NodeList nodes) {
30
        this.nodes = nodes;
31
    }
32
33
    public boolean hasNext() {
34
        return index < nodes.getLength();
35
    }
36
37
    public Object next() {
38
        return nodes.item(index++);
39
    }
40
41
    Node current() {
42
        return nodes.item(index);
43
    }
44
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathFactory.java (+29 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
20
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
21
22
/**
23
 */
24
public class XalanXPathFactory extends JSTLXPathFactory {
25
    @Override
26
    public JSTLXPathCompiler newCompiler() {
27
        return new XalanXPathCompiler();
28
    }
29
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathCompiler.java (+37 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import javax.xml.transform.TransformerException;
20
21
import org.apache.taglibs.standard.xpath.InvalidXPathException;
22
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
23
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
24
import org.apache.xpath.XPath;
25
26
/**
27
 */
28
public class XalanXPathCompiler implements JSTLXPathCompiler {
29
    public JSTLXPathExpression compile(String expression) throws InvalidXPathException {
30
        try {
31
            XPath xpath = new XPath(expression, null, null, XPath.SELECT);
32
            return new XalanXPathExpression(xpath);
33
        } catch (TransformerException e) {
34
            throw new InvalidXPathException(e);
35
        }
36
    }
37
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/JSTLVariableStack.java (+61 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import javax.servlet.jsp.PageContext;
20
import javax.xml.XMLConstants;
21
import javax.xml.transform.TransformerException;
22
23
import org.apache.taglibs.standard.xpath.JSTLVariableResolver;
24
import org.apache.xml.utils.QName;
25
import org.apache.xpath.VariableStack;
26
import org.apache.xpath.XPathContext;
27
import org.apache.xpath.objects.XObject;
28
import org.apache.xpath.objects.XObjectFactory;
29
30
/**
31
 */
32
public class JSTLVariableStack extends VariableStack {
33
34
    private final JSTLVariableResolver resolver;
35
36
    public JSTLVariableStack(PageContext pageContext) {
37
        super(2);
38
        resolver = new JSTLVariableResolver();
39
        resolver.setPageContext(pageContext);
40
    }
41
42
    @Override
43
    public XObject getVariableOrParam(XPathContext xctxt, QName qname) throws TransformerException {
44
        String uri = qname.getNamespaceURI();
45
        if (uri == null) {
46
            uri = XMLConstants.NULL_NS_URI;
47
        }
48
        String namespaceURI = resolver.getNamespaceURI(uri);
49
        String localPart = qname.getLocalPart();
50
        javax.xml.namespace.QName name = new javax.xml.namespace.QName(namespaceURI, localPart);
51
        Object value = resolver.resolveVariable(name);
52
        if (value == null) {
53
            throw new TransformerException("Variable " + qname + " not found");
54
        }
55
        return coerceToXPath(value, xctxt);
56
    }
57
58
    XObject coerceToXPath(Object value, XPathContext xctxt) {
59
        return XObjectFactory.create(value, xctxt);
60
    }
61
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathExpression.java (+152 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.PageContext;
21
import javax.xml.parsers.DocumentBuilder;
22
import javax.xml.parsers.DocumentBuilderFactory;
23
import javax.xml.parsers.ParserConfigurationException;
24
import javax.xml.transform.TransformerException;
25
26
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
27
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
28
import org.apache.xpath.VariableStack;
29
import org.apache.xpath.XPath;
30
import org.apache.xpath.XPathContext;
31
import org.apache.xpath.objects.XBoolean;
32
import org.apache.xpath.objects.XNodeSet;
33
import org.apache.xpath.objects.XNumber;
34
import org.apache.xpath.objects.XObject;
35
import org.apache.xpath.objects.XString;
36
import org.w3c.dom.Document;
37
import org.w3c.dom.Node;
38
import org.w3c.dom.NodeList;
39
40
/**
41
 */
42
public class XalanXPathExpression implements JSTLXPathExpression {
43
    private final XPath xpath;
44
    private static final DocumentBuilderFactory dbf;
45
46
    static {
47
        dbf = DocumentBuilderFactory.newInstance();
48
        dbf.setNamespaceAware(true);
49
        dbf.setValidating(false);
50
    }
51
52
    public XalanXPathExpression(XPath xpath) {
53
        this.xpath = xpath;
54
    }
55
56
    public boolean evaluateBoolean(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
57
        try {
58
            return evaluate(context, pageContext).bool();
59
        } catch (TransformerException e) {
60
            throw new JspTagException(e);
61
        }
62
    }
63
64
    public String evaluateString(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
65
        try {
66
            return evaluate(context, pageContext).str();
67
        } catch (TransformerException e) {
68
            throw new JspTagException(e);
69
        }
70
    }
71
72
    public Object evaluateObject(JSTLXPathContext context, PageContext pageContext) throws JspTagException {
73
        try {
74
            XObject result = evaluate(context, pageContext);
75
            return coerceToJava(result);
76
        } catch (TransformerException e) {
77
            throw new JspTagException(e);
78
        }
79
    }
80
81
    public JSTLXPathContext iterate(JSTLXPathContext jstlContext, PageContext pageContext) throws JspTagException {
82
        XPathContext xpathContext;
83
        int node;
84
        if (jstlContext == null) {
85
            xpathContext = newContext(pageContext);
86
            Node root = getEmptyDocument();
87
            node = xpathContext.getDTMHandleFromNode(root);
88
        } else {
89
            XalanXPathContext context = (XalanXPathContext) jstlContext;
90
            xpathContext = context.getContext();
91
            node = context.getCurrentNode();
92
        }
93
        try {
94
            XObject result = xpath.execute(xpathContext, node, null);
95
            return new XalanXPathContext(xpathContext, result);
96
        } catch (TransformerException e) {
97
            throw new JspTagException(e);
98
        }
99
    }
100
101
    XObject evaluate(JSTLXPathContext jstlContext, PageContext pageContext) throws TransformerException {
102
        XPathContext xpathContext;
103
        int dtm;
104
        if (jstlContext == null) {
105
            xpathContext = newContext(pageContext);
106
            Node node = getEmptyDocument();
107
            dtm = xpathContext.getDTMHandleFromNode(node);
108
        } else {
109
            XalanXPathContext context = (XalanXPathContext) jstlContext;
110
            xpathContext = context.getContext();
111
            dtm = context.getCurrentNode();
112
        }
113
        return xpath.execute(xpathContext, dtm, null);
114
    }
115
116
    XPathContext newContext(PageContext pageContext) {
117
        XPathContext context = new XPathContext(false);
118
        VariableStack variableStack = new JSTLVariableStack(pageContext);
119
        context.setVarStack(variableStack);
120
        return context;
121
    }
122
123
    Object coerceToJava(XObject xo) throws TransformerException {
124
        if (xo instanceof XBoolean) {
125
            return xo.bool();
126
        } else if (xo instanceof XNumber) {
127
            return xo.num();
128
        } else if (xo instanceof XString) {
129
            return xo.str();
130
        } else if (xo instanceof XNodeSet) {
131
            NodeList nodes = xo.nodelist();
132
            // if there is only one node in the nodeset return that rather than the list
133
            if (nodes.getLength() == 1) {
134
                return nodes.item(0);
135
            } else {
136
                return nodes;
137
            }
138
        } else {
139
            // unexpected result type
140
            throw new AssertionError();
141
        }
142
    }
143
144
    Document getEmptyDocument() {
145
        try {
146
            DocumentBuilder db = dbf.newDocumentBuilder();
147
            return db.newDocument();
148
        } catch (ParserConfigurationException e) {
149
            throw new AssertionError();
150
        }
151
    }
152
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/xalan/XalanXPathContext.java (+53 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath.xalan;
18
19
import javax.xml.transform.TransformerException;
20
21
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
22
import org.apache.xml.dtm.DTMIterator;
23
import org.apache.xpath.XPathContext;
24
import org.apache.xpath.objects.XObject;
25
26
/**
27
 */
28
public class XalanXPathContext implements JSTLXPathContext {
29
    private final XPathContext context;
30
    private final DTMIterator iterator;
31
32
    public XalanXPathContext(XPathContext context, XObject nodes) throws TransformerException {
33
        this.context = context;
34
        iterator = nodes.iter();
35
    }
36
37
    public boolean hasNext() {
38
        return iterator.getCurrentPos() < iterator.getLength();
39
    }
40
41
    public Object next() {
42
        int next = iterator.nextNode();
43
        return iterator.getDTM(next).getNode(next);
44
    }
45
46
    XPathContext getContext() {
47
        return context;
48
    }
49
50
    int getCurrentNode() {
51
        return iterator.getCurrentNode();
52
    }
53
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLVariableResolver.java (+163 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
import javax.servlet.http.Cookie;
20
import javax.servlet.http.HttpServletRequest;
21
import javax.servlet.jsp.PageContext;
22
import javax.xml.XMLConstants;
23
import javax.xml.namespace.NamespaceContext;
24
import javax.xml.namespace.QName;
25
import javax.xml.xpath.XPathVariableResolver;
26
import java.util.HashMap;
27
import java.util.Iterator;
28
import java.util.Map;
29
30
/**
31
 */
32
public class JSTLVariableResolver implements XPathVariableResolver, NamespaceContext {
33
34
    private static enum Scope {
35
        JSP,
36
        PARAM,
37
        HEADER,
38
        COOKIE,
39
        INITPARAM,
40
        PAGE,
41
        REQUEST,
42
        SESSION,
43
        APPLICATION
44
    }
45
46
    // Namespace URIs for JSTL implicit variables
47
    private static final String PARAM_NS_URL = "http://java.sun.com/jstl/xpath/param";
48
    private static final String HEADER_NS_URL = "http://java.sun.com/jstl/xpath/header";
49
    private static final String COOKIE_NS_URL = "http://java.sun.com/jstl/xpath/cookie";
50
    private static final String INITPARAM_NS_URL = "http://java.sun.com/jstl/xpath/initParam";
51
    private static final String PAGE_NS_URL = "http://java.sun.com/jstl/xpath/page";
52
    private static final String REQUEST_NS_URL = "http://java.sun.com/jstl/xpath/request";
53
    private static final String SESSION_NS_URL = "http://java.sun.com/jstl/xpath/session";
54
    private static final String APP_NS_URL = "http://java.sun.com/jstl/xpath/app";
55
56
    // Prefixes for JSTL implicit variables
57
    private static final String PARAM_PREFIX = "param";
58
    private static final String HEADER_PREFIX = "header";
59
    private static final String COOKIE_PREFIX = "cookie";
60
    private static final String INITPARAM_PREFIX = "initParam";
61
    private static final String PAGE_PREFIX = "pageScope";
62
    private static final String REQUEST_PREFIX = "requestScope";
63
    private static final String SESSION_PREFIX = "sessionScope";
64
    private static final String APP_PREFIX = "applicationScope";
65
66
    // map prefixes to namespaces
67
    private static final Map<String, String> NAMESPACES;
68
69
    static {
70
        NAMESPACES = new HashMap<String, String>(8);
71
        NAMESPACES.put(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI);
72
        NAMESPACES.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
73
        NAMESPACES.put(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI);
74
        NAMESPACES.put(PARAM_PREFIX, PARAM_NS_URL);
75
        NAMESPACES.put(HEADER_PREFIX, HEADER_NS_URL);
76
        NAMESPACES.put(COOKIE_PREFIX, COOKIE_NS_URL);
77
        NAMESPACES.put(INITPARAM_PREFIX, INITPARAM_NS_URL);
78
        NAMESPACES.put(PAGE_PREFIX, PAGE_NS_URL);
79
        NAMESPACES.put(REQUEST_PREFIX, REQUEST_NS_URL);
80
        NAMESPACES.put(SESSION_PREFIX, SESSION_NS_URL);
81
        NAMESPACES.put(APP_PREFIX, APP_NS_URL);
82
    }
83
84
    // map namespaces to scopes
85
    private static final Map<String, Scope> SCOPES;
86
87
    static {
88
        SCOPES = new HashMap<String, Scope>(8);
89
        SCOPES.put(XMLConstants.NULL_NS_URI, Scope.JSP);
90
        SCOPES.put(PARAM_NS_URL, Scope.PARAM);
91
        SCOPES.put(HEADER_NS_URL, Scope.HEADER);
92
        SCOPES.put(COOKIE_NS_URL, Scope.COOKIE);
93
        SCOPES.put(INITPARAM_NS_URL, Scope.INITPARAM);
94
        SCOPES.put(PAGE_NS_URL, Scope.PAGE);
95
        SCOPES.put(REQUEST_NS_URL, Scope.REQUEST);
96
        SCOPES.put(SESSION_NS_URL, Scope.SESSION);
97
        SCOPES.put(APP_NS_URL, Scope.APPLICATION);
98
    }
99
100
101
    private PageContext pageContext;
102
103
    public void setPageContext(PageContext pageContext) {
104
        this.pageContext = pageContext;
105
    }
106
107
    public Object resolveVariable(QName variableName) {
108
        String name = variableName.getLocalPart();
109
        Scope scope = SCOPES.get(variableName.getNamespaceURI());
110
        if (scope == null) {
111
            return null;
112
        }
113
        switch (scope) {
114
            case JSP:
115
                return pageContext.findAttribute(name);
116
            case PARAM:
117
                return pageContext.getRequest().getParameter(name);
118
            case HEADER:
119
                return ((HttpServletRequest) pageContext.getRequest()).getHeader(name);
120
            case COOKIE:
121
                Cookie[] cookies = ((HttpServletRequest) pageContext.getRequest()).getCookies();
122
                if (cookies != null) {
123
                    for (Cookie cookie : cookies) {
124
                        if (cookie.getName().equals(name)) {
125
                            return cookie.getValue();
126
                        }
127
                    }
128
                }
129
                return null;
130
            case INITPARAM:
131
                return pageContext.getServletContext().getInitParameter(name);
132
            case PAGE:
133
                return pageContext.getAttribute(name, PageContext.PAGE_SCOPE);
134
            case REQUEST:
135
                return pageContext.getAttribute(name, PageContext.REQUEST_SCOPE);
136
            case SESSION:
137
                return pageContext.getAttribute(name, PageContext.SESSION_SCOPE);
138
            case APPLICATION:
139
                return pageContext.getAttribute(name, PageContext.APPLICATION_SCOPE);
140
            default:
141
                throw new AssertionError();
142
        }
143
    }
144
145
    public String getNamespaceURI(String prefix) {
146
        if (prefix == null) {
147
            throw new IllegalArgumentException("prefix is null");
148
        }
149
        String uri = NAMESPACES.get(prefix);
150
        if (uri != null) {
151
            return uri;
152
        }
153
        return XMLConstants.NULL_NS_URI;
154
    }
155
156
    public String getPrefix(String namespaceURI) {
157
        throw new UnsupportedOperationException();
158
    }
159
160
    public Iterator getPrefixes(String namespaceURI) {
161
        throw new UnsupportedOperationException();
162
    }
163
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathContext.java (+24 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
/**
20
 */
21
public interface JSTLXPathContext {
22
    boolean hasNext();
23
    Object next();
24
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathFactory.java (+32 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
import org.apache.taglibs.standard.xpath.xalan.XalanXPathFactory;
20
21
/**
22
 */
23
public abstract class JSTLXPathFactory {
24
25
    private static final JSTLXPathFactory factory = new XalanXPathFactory();
26
27
    public static JSTLXPathFactory getFactory() {
28
        return factory;
29
    }
30
31
    public abstract JSTLXPathCompiler newCompiler();
32
}
0
  + native
33
  + native
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/InvalidXPathException.java (+36 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
/**
20
 */
21
public class InvalidXPathException extends RuntimeException {
22
    public InvalidXPathException() {
23
    }
24
25
    public InvalidXPathException(String s) {
26
        super(s);
27
    }
28
29
    public InvalidXPathException(String s, Throwable throwable) {
30
        super(s, throwable);
31
    }
32
33
    public InvalidXPathException(Throwable throwable) {
34
        super(throwable);
35
    }
36
}
(-)impl/src/main/java/org/apache/taglibs/standard/xpath/JSTLXPathCompiler.java (+31 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.xpath;
18
19
/**
20
 */
21
public interface JSTLXPathCompiler {
22
23
    /**
24
     * Pre-compiles an XPath expression for future evaluation;
25
     *
26
     * @param xpath the xpath to compile
27
     * @return an JSTLXPathExpression that can be used to evaluate the XPath
28
     * @throws InvalidXPathException if the supplied XPath is not valid
29
     */
30
    JSTLXPathExpression compile(String xpath) throws InvalidXPathException;
31
}
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java (-896 lines)
Lines 1-896 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
package org.apache.taglibs.standard.tag.common.xml;
19
20
import java.util.Enumeration;
21
import java.util.HashMap;
22
import java.util.List;
23
import java.util.Vector;
24
25
import javax.servlet.http.Cookie;
26
import javax.servlet.http.HttpServletRequest;
27
import javax.servlet.jsp.JspTagException;
28
import javax.servlet.jsp.PageContext;
29
import javax.servlet.jsp.tagext.Tag;
30
import javax.servlet.jsp.tagext.TagSupport;
31
import javax.xml.parsers.DocumentBuilder;
32
import javax.xml.parsers.DocumentBuilderFactory;
33
import javax.xml.transform.TransformerException;
34
35
import org.apache.taglibs.standard.resources.Resources;
36
import org.apache.xml.utils.QName;
37
import org.apache.xpath.VariableStack;
38
import org.apache.xpath.XPathContext;
39
import org.apache.xpath.objects.XBoolean;
40
import org.apache.xpath.objects.XNodeSetForDOM;
41
import org.apache.xpath.objects.XNumber;
42
import org.apache.xpath.objects.XObject;
43
import org.apache.xpath.objects.XString;
44
import org.w3c.dom.DOMImplementation;
45
import org.w3c.dom.Document;
46
import org.w3c.dom.Element;
47
import org.w3c.dom.Node;
48
import org.w3c.dom.NodeList;
49
50
/**
51
 * <p>Support for tag handlers that evaluate XPath expressions.</p>
52
 *
53
 * @author Shawn Bayern
54
 * @author Ramesh Mandava ( ramesh.mandava@sun.com )
55
 * @author Pierre Delisle ( pierre.delisle@sun.com )
56
 */
57
// would ideally be a base class, but some of our user handlers already
58
// have their own parents
59
public class XPathUtil {
60
61
    //*********************************************************************
62
    // Constructor
63
64
    /**
65
     * Constructs a new XPathUtil object associated with the given
66
     * PageContext.
67
     */
68
    public XPathUtil(PageContext pc) {
69
        pageContext = pc;
70
    }
71
72
    int globalVarSize = 0;
73
74
    public Vector getVariableQNames() {
75
76
        globalVarSize = 0;
77
        Vector variableVector = new Vector();
78
        // Now construct attributes in different scopes
79
        Enumeration enum_ = pageContext.getAttributeNamesInScope(
80
                PageContext.PAGE_SCOPE);
81
        while (enum_.hasMoreElements()) {
82
            String varName = (String) enum_.nextElement();
83
            QName varQName = new QName(PAGE_NS_URL, PAGE_P, varName);
84
            //Adding both namespace qualified QName and just localName
85
            variableVector.addElement(varQName);
86
            globalVarSize++;
87
88
            variableVector.addElement(new QName(null, varName));
89
            globalVarSize++;
90
        }
91
        enum_ = pageContext.getAttributeNamesInScope(
92
                PageContext.REQUEST_SCOPE);
93
        while (enum_.hasMoreElements()) {
94
            String varName = (String) enum_.nextElement();
95
            QName varQName = new QName(REQUEST_NS_URL, REQUEST_P, varName);
96
            //Adding both namespace qualified QName and just localName
97
            variableVector.addElement(varQName);
98
            globalVarSize++;
99
            variableVector.addElement(new QName(null, varName));
100
            globalVarSize++;
101
        }
102
103
        if (pageContext.getSession() != null) {
104
            // we may have a page directive preventing session creation/access
105
            // do not attempt to retrieve attribute names in session scope
106
            // @see [ http://issues.apache.org/bugzilla/show_bug.cgi?id=35216 ]
107
            enum_ = pageContext.getAttributeNamesInScope(
108
                    PageContext.SESSION_SCOPE);
109
            while (enum_.hasMoreElements()) {
110
                String varName = (String) enum_.nextElement();
111
                QName varQName = new QName(SESSION_NS_URL, SESSION_P, varName);
112
                //Adding both namespace qualified QName and just localName
113
                variableVector.addElement(varQName);
114
                globalVarSize++;
115
                variableVector.addElement(new QName(null, varName));
116
                globalVarSize++;
117
            }
118
        }
119
120
        enum_ = pageContext.getAttributeNamesInScope(
121
                PageContext.APPLICATION_SCOPE);
122
        while (enum_.hasMoreElements()) {
123
            String varName = (String) enum_.nextElement();
124
            QName varQName = new QName(APP_NS_URL, APP_P, varName);
125
            //Adding both namespace qualified QName and just localName
126
            variableVector.addElement(varQName);
127
            globalVarSize++;
128
            variableVector.addElement(new QName(null, varName));
129
            globalVarSize++;
130
        }
131
        enum_ = pageContext.getRequest().getParameterNames();
132
        while (enum_.hasMoreElements()) {
133
            String varName = (String) enum_.nextElement();
134
            QName varQName = new QName(PARAM_NS_URL, PARAM_P, varName);
135
            //Adding both namespace qualified QName and just localName
136
            variableVector.addElement(varQName);
137
            globalVarSize++;
138
        }
139
        enum_ = pageContext.getServletContext().getInitParameterNames();
140
        while (enum_.hasMoreElements()) {
141
            String varName = (String) enum_.nextElement();
142
            QName varQName = new QName(INITPARAM_NS_URL, INITPARAM_P, varName);
143
            //Adding both namespace qualified QName and just localName
144
            variableVector.addElement(varQName);
145
            globalVarSize++;
146
        }
147
        enum_ = ((HttpServletRequest) pageContext.getRequest()).getHeaderNames();
148
        while (enum_.hasMoreElements()) {
149
            String varName = (String) enum_.nextElement();
150
            QName varQName = new QName(HEADER_NS_URL, HEADER_P, varName);
151
            //Adding namespace qualified QName 
152
            variableVector.addElement(varQName);
153
            globalVarSize++;
154
        }
155
        Cookie[] c = ((HttpServletRequest) pageContext.getRequest()).getCookies();
156
        if (c != null) {
157
            for (int i = 0; i < c.length; i++) {
158
                String varName = c[i].getName();
159
                QName varQName = new QName(COOKIE_NS_URL, COOKIE_P, varName);
160
                //Adding namespace qualified QName 
161
                variableVector.addElement(varQName);
162
                globalVarSize++;
163
            }
164
        }
165
166
        return variableVector;
167
168
    }
169
170
    //*********************************************************************
171
    // Support for JSTL variable resolution
172
173
    // The URLs
174
    private static final String PAGE_NS_URL
175
            = "http://java.sun.com/jstl/xpath/page";
176
    private static final String REQUEST_NS_URL
177
            = "http://java.sun.com/jstl/xpath/request";
178
    private static final String SESSION_NS_URL
179
            = "http://java.sun.com/jstl/xpath/session";
180
    private static final String APP_NS_URL
181
            = "http://java.sun.com/jstl/xpath/app";
182
    private static final String PARAM_NS_URL
183
            = "http://java.sun.com/jstl/xpath/param";
184
    private static final String INITPARAM_NS_URL
185
            = "http://java.sun.com/jstl/xpath/initParam";
186
    private static final String COOKIE_NS_URL
187
            = "http://java.sun.com/jstl/xpath/cookie";
188
    private static final String HEADER_NS_URL
189
            = "http://java.sun.com/jstl/xpath/header";
190
191
    // The prefixes
192
    private static final String PAGE_P = "pageScope";
193
    private static final String REQUEST_P = "requestScope";
194
    private static final String SESSION_P = "sessionScope";
195
    private static final String APP_P = "applicationScope";
196
    private static final String PARAM_P = "param";
197
    private static final String INITPARAM_P = "initParam";
198
    private static final String COOKIE_P = "cookie";
199
    private static final String HEADER_P = "header";
200
201
    /**
202
     * org.apache.xpath.VariableStack defines a class to keep track of a stack
203
     * for template arguments and variables.
204
     * JstlVariableContext customizes it so it handles JSTL custom
205
     * variable-mapping rules.
206
     */
207
    protected class JstlVariableContext extends org.apache.xpath.VariableStack {
208
209
        public JstlVariableContext() {
210
            super();
211
        }
212
213
        /**
214
         * Get a variable as an XPath object based on it's qualified name.
215
         * We override the base class method so JSTL's custom variable-mapping
216
         * rules can be applied.
217
         *
218
         * @param xctxt The XPath context. @@@ we don't use it...
219
         *              (from xalan: which must be passed in order to lazy evaluate variables.)
220
         * @param qname The qualified name of the variable.
221
         */
222
        @Override
223
        public XObject getVariableOrParam(
224
                XPathContext xctxt,
225
                org.apache.xml.utils.QName qname)
226
                throws javax.xml.transform.TransformerException, UnresolvableException {
227
            //p( "***********************************getVariableOrParam begin****");
228
            String namespace = qname.getNamespaceURI();
229
            String prefix = qname.getPrefix();
230
            String localName = qname.getLocalName();
231
232
            //p("namespace:prefix:localname=>"+ namespace
233
            //     + ":" + prefix +":" + localName );
234
235
            try {
236
                Object varObject = getVariableValue(namespace, prefix, localName);
237
238
239
                //XObject varObject = myvs.getVariableOrParam( xpathSupport, varQName);
240
                XObject newXObject = new XObject(varObject);
241
242
                if (Class.forName("org.w3c.dom.Document").isInstance(varObject)) {
243
244
                    NodeList nl = ((Document) varObject).getChildNodes();
245
                    // To allow non-welformed document
246
                    Vector nodeVector = new Vector();
247
                    for (int i = 0; i < nl.getLength(); i++) {
248
                        Node currNode = nl.item(i);
249
                        if (currNode.getNodeType() == Node.ELEMENT_NODE) {
250
                            nodeVector.addElement(currNode);
251
                        }
252
                    }
253
                    JSTLNodeList jstlNodeList = new JSTLNodeList(nodeVector);
254
                    newXObject = new XNodeSetForDOM(jstlNodeList, xctxt);
255
256
                    return newXObject;
257
258
                }
259
                if (Class.forName(
260
                        "org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(
261
                        varObject)) {
262
                    JSTLNodeList jstlNodeList = (JSTLNodeList) varObject;
263
                    if ((jstlNodeList.getLength() == 1) &&
264
                            (!Class.forName("org.w3c.dom.Node").isInstance(jstlNodeList.elementAt(0)))) {
265
                        varObject = jstlNodeList.elementAt(0);
266
                        //Now we need to allow this primitive type to be coverted 
267
                        // to type which Xalan XPath understands 
268
                    } else {
269
                        return new XNodeSetForDOM(jstlNodeList, xctxt);
270
                    }
271
                }
272
                if (Class.forName("org.w3c.dom.Node").isInstance(varObject)) {
273
                    newXObject = new XNodeSetForDOM(new JSTLNodeList((Node) varObject), xctxt);
274
                } else if (Class.forName("java.lang.String").isInstance(varObject)) {
275
                    newXObject = new XString((String) varObject);
276
                } else if (Class.forName("java.lang.Boolean").isInstance(varObject)) {
277
                    newXObject = new XBoolean((Boolean) varObject);
278
                } else if (Class.forName("java.lang.Number").isInstance(varObject)) {
279
                    newXObject = new XNumber((Number) varObject);
280
                }
281
282
                return newXObject;
283
                // myvs.setGlobalVariable( i, newXObject );
284
            } catch (ClassNotFoundException cnfe) {
285
                // This shouldn't happen (TODO: LOG)
286
                System.out.println("CLASS NOT FOUND EXCEPTION :" + cnfe);
287
            }
288
            //System.out.println("*****getVariableOrParam returning *null*" );
289
            return null;
290
        }
291
292
        /**
293
         * Retrieve an XPath's variable value using JSTL's custom
294
         * variable-mapping rules
295
         */
296
        public Object getVariableValue(
297
                String namespace,
298
                String prefix,
299
                String localName)
300
                throws UnresolvableException {
301
            // p("resolving: ns=" + namespace + " prefix=" + prefix + " localName=" + localName);
302
            // We can match on namespace with Xalan but leaving as is
303
            // [ I 'd prefer to match on namespace, but this doesn't appear
304
            // to work in Jaxen]
305
            if (prefix == null || prefix.equals("")) {
306
                return notNull(
307
                        pageContext.findAttribute(localName),
308
                        prefix,
309
                        localName);
310
            } else if (prefix.equals(PAGE_P)) {
311
                return notNull(
312
                        pageContext.getAttribute(localName, PageContext.PAGE_SCOPE),
313
                        prefix,
314
                        localName);
315
            } else if (prefix.equals(REQUEST_P)) {
316
                return notNull(
317
                        pageContext.getAttribute(localName,
318
                                PageContext.REQUEST_SCOPE),
319
                        prefix,
320
                        localName);
321
            } else if (prefix.equals(SESSION_P)) {
322
                return notNull(
323
                        pageContext.getAttribute(localName,
324
                                PageContext.SESSION_SCOPE),
325
                        prefix,
326
                        localName);
327
            } else if (prefix.equals(APP_P)) {
328
                return notNull(
329
                        pageContext.getAttribute(localName,
330
                                PageContext.APPLICATION_SCOPE),
331
                        prefix,
332
                        localName);
333
            } else if (prefix.equals(PARAM_P)) {
334
                return notNull(
335
                        pageContext.getRequest().getParameter(localName),
336
                        prefix,
337
                        localName);
338
            } else if (prefix.equals(INITPARAM_P)) {
339
                return notNull(
340
                        pageContext.getServletContext().
341
                                getInitParameter(localName),
342
                        prefix,
343
                        localName);
344
            } else if (prefix.equals(HEADER_P)) {
345
                HttpServletRequest hsr =
346
                        (HttpServletRequest) pageContext.getRequest();
347
                return notNull(
348
                        hsr.getHeader(localName),
349
                        prefix,
350
                        localName);
351
            } else if (prefix.equals(COOKIE_P)) {
352
                HttpServletRequest hsr =
353
                        (HttpServletRequest) pageContext.getRequest();
354
                Cookie[] c = hsr.getCookies();
355
                for (int i = 0; i < c.length; i++) {
356
                    if (c[i].getName().equals(localName)) {
357
                        return c[i].getValue();
358
                    }
359
                }
360
                throw new UnresolvableException("$" + prefix + ":" + localName);
361
            } else {
362
                throw new UnresolvableException("$" + prefix + ":" + localName);
363
            }
364
        }
365
366
        /**
367
         * Validate that the Object returned is not null. If it is
368
         * null, throw an exception.
369
         */
370
        private Object notNull(Object o, String prefix, String localName)
371
                throws UnresolvableException {
372
            if (o == null) {
373
                throw new UnresolvableException("$" + (prefix == null ? "" : prefix + ":") + localName);
374
            }
375
            //p("resolved to: " + o);
376
            return o;
377
        }
378
    }
379
380
    //*********************************************************************
381
    // Support for XPath evaluation
382
383
    private PageContext pageContext;
384
    private static HashMap exprCache;
385
    private static JSTLPrefixResolver jstlPrefixResolver = null;
386
387
    /**
388
     * Initialize globally useful data.
389
     */
390
    private synchronized static void staticInit() {
391
        if (jstlPrefixResolver == null) {
392
            // register supported namespaces
393
            jstlPrefixResolver = new JSTLPrefixResolver();
394
            jstlPrefixResolver.addNamespace("pageScope", PAGE_NS_URL);
395
            jstlPrefixResolver.addNamespace("requestScope", REQUEST_NS_URL);
396
            jstlPrefixResolver.addNamespace("sessionScope", SESSION_NS_URL);
397
            jstlPrefixResolver.addNamespace("applicationScope", APP_NS_URL);
398
            jstlPrefixResolver.addNamespace("param", PARAM_NS_URL);
399
            jstlPrefixResolver.addNamespace("initParam", INITPARAM_NS_URL);
400
            jstlPrefixResolver.addNamespace("header", HEADER_NS_URL);
401
            jstlPrefixResolver.addNamespace("cookie", COOKIE_NS_URL);
402
403
404
            // create a HashMap to cache the expressions
405
            exprCache = new HashMap();
406
        }
407
    }
408
409
    static DocumentBuilderFactory dbf = null;
410
    static DocumentBuilder db = null;
411
    static Document d = null;
412
413
    static Document getDummyDocument() {
414
        try {
415
            if (dbf == null) {
416
                dbf = DocumentBuilderFactory.newInstance();
417
                dbf.setNamespaceAware(true);
418
                dbf.setValidating(false);
419
            }
420
            db = dbf.newDocumentBuilder();
421
422
            DOMImplementation dim = db.getDOMImplementation();
423
            d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null);
424
            //d = db.newDocument();
425
            return d;
426
        } catch (Exception e) {
427
            e.printStackTrace();
428
        }
429
        return null;
430
    }
431
432
    static Document getDummyDocumentWithoutRoot() {
433
        try {
434
            if (dbf == null) {
435
                dbf = DocumentBuilderFactory.newInstance();
436
                dbf.setNamespaceAware(true);
437
                dbf.setValidating(false);
438
            }
439
            db = dbf.newDocumentBuilder();
440
441
            d = db.newDocument();
442
            return d;
443
        } catch (Exception e) {
444
            e.printStackTrace();
445
        }
446
        return null;
447
    }
448
449
    private static Document getDocumentForNode(Node node) {
450
        Document doc = getDummyDocumentWithoutRoot();
451
        Node importedNode = doc.importNode(node, true);
452
        doc.appendChild(importedNode);
453
        return doc;
454
    }
455
456
    // The following variable is used for holding the modified xpath string
457
    // when adapting parameter for Xalan XPath engine, where we need to have
458
    // a Non null context node.
459
    String modifiedXPath = null;
460
461
462
    /**
463
     * Evaluate an XPath expression to a String value.
464
     */
465
    public String valueOf(Node n, String xpath) throws JspTagException {
466
        //p("******** valueOf(" + n + ", " + xpath + ")");
467
        staticInit();
468
        // @@@ but where do we set the Pag4eContext for the varaiblecontext?
469
        JstlVariableContext vs = new JstlVariableContext();
470
        XPathContext xpathSupport = new XPathContext();
471
        xpathSupport.setVarStack(vs);
472
473
        Vector varVector = fillVarStack(vs, xpathSupport);
474
475
        Node contextNode = adaptParamsForXalan(vs, n, xpath.trim());
476
477
        xpath = modifiedXPath;
478
479
        //p("******** valueOf: modified xpath: " + xpath);
480
481
        XObject result = JSTLXPathAPI.eval(contextNode, xpath,
482
                jstlPrefixResolver, xpathSupport, varVector);
483
484
485
        //p("******Result TYPE => " + result.getTypeString() );
486
487
        String resultString = result.str();
488
        //p("******** valueOf: after eval: " + resultString);
489
490
        return resultString;
491
492
    }
493
494
    /**
495
     * Evaluate an XPath expression to a boolean value.
496
     */
497
    public boolean booleanValueOf(Node n, String xpath)
498
            throws JspTagException {
499
500
        staticInit();
501
        JstlVariableContext vs = new JstlVariableContext();
502
        XPathContext xpathSupport = new XPathContext();
503
        xpathSupport.setVarStack(vs);
504
505
        Vector varVector = fillVarStack(vs, xpathSupport);
506
507
        Node contextNode = adaptParamsForXalan(vs, n, xpath.trim());
508
        xpath = modifiedXPath;
509
510
        XObject result = JSTLXPathAPI.eval(contextNode, xpath,
511
                jstlPrefixResolver, xpathSupport, varVector);
512
513
        try {
514
            return result.bool();
515
        } catch (TransformerException ex) {
516
            throw new JspTagException(
517
                    Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);
518
        }
519
    }
520
521
    /**
522
     * Evaluate an XPath expression to a List of nodes.
523
     */
524
    public List selectNodes(Node n, String xpath) throws JspTagException {
525
526
        staticInit();
527
        JstlVariableContext vs = new JstlVariableContext();
528
        XPathContext xpathSupport = new XPathContext();
529
        xpathSupport.setVarStack(vs);
530
531
        Vector varVector = fillVarStack(vs, xpathSupport);
532
533
        Node contextNode = adaptParamsForXalan(vs, n, xpath.trim());
534
        xpath = modifiedXPath;
535
536
        XObject result = JSTLXPathAPI.eval(contextNode, xpath,
537
                jstlPrefixResolver, xpathSupport, varVector);
538
        try {
539
            NodeList nl = JSTLXPathAPI.getNodeList(result);
540
            return new JSTLNodeList(nl);
541
        } catch (JspTagException e) {
542
            try {
543
                //If result can't be converted to NodeList we receive exception
544
                // In this case we may have single primitive value as the result
545
                // Populating List with this value ( String, Boolean or Number )
546
547
                //System.out.println("JSTLXPathAPI.getNodeList thrown exception:"+ e);
548
                Vector vector = new Vector();
549
                Object resultObject = null;
550
                if (result.getType() == XObject.CLASS_BOOLEAN) {
551
                    resultObject = result.bool();
552
                } else if (result.getType() == XObject.CLASS_NUMBER) {
553
                    resultObject = result.num();
554
                } else if (result.getType() == XObject.CLASS_STRING) {
555
                    resultObject = result.str();
556
                }
557
558
                vector.add(resultObject);
559
                return new JSTLNodeList(vector);
560
            } catch (TransformerException te) {
561
                throw new JspTagException(te.toString(), te);
562
            }
563
        }
564
565
566
    }
567
568
    /**
569
     * Evaluate an XPath expression to a single node.
570
     */
571
    public Node selectSingleNode(Node n, String xpath)
572
            throws JspTagException {
573
        //p("selectSingleNode of XPathUtil = passed node:" +
574
        //   "xpath => " + n + " : " + xpath );
575
576
        staticInit();
577
        JstlVariableContext vs = new JstlVariableContext();
578
        XPathContext xpathSupport = new XPathContext();
579
        xpathSupport.setVarStack(vs);
580
581
        Vector varVector = fillVarStack(vs, xpathSupport);
582
583
        Node contextNode = adaptParamsForXalan(vs, n, xpath.trim());
584
        xpath = modifiedXPath;
585
586
        return (Node) JSTLXPathAPI.selectSingleNode(contextNode, xpath,
587
                jstlPrefixResolver, xpathSupport);
588
    }
589
590
    /**
591
     * Returns a locally appropriate context given a node.
592
     */
593
    private VariableStack getLocalContext() {
594
        // set up instance-specific contexts
595
        VariableStack vc = new JstlVariableContext();
596
        return vc;
597
    }
598
599
    //*********************************************************************
600
    // Adapt XPath expression for integration with Xalan
601
602
    /**
603
     * To evaluate an XPath expression using Xalan, we need
604
     * to create an XPath object, which wraps an expression object and provides
605
     * general services for execution of that expression.
606
     * <p>An XPath object can be instantiated with the following information:
607
     * - XPath expression to evaluate
608
     * - SourceLocator
609
     * (reports where an error occurred in the XML source or
610
     * transformation instructions)
611
     * - PrefixResolver
612
     * (resolve prefixes to namespace URIs)
613
     * - type
614
     * (one of SELECT or MATCH)
615
     * - ErrorListener
616
     * (customized error handling)
617
     * <p>Execution of the XPath expression represented by an XPath object
618
     * is done via method execute which takes the following parameters:
619
     * - XPathContext
620
     * The execution context
621
     * - Node contextNode
622
     * The node that "." expresses
623
     * - PrefixResolver namespaceContext
624
     * The context in which namespaces in the XPath are supposed to be
625
     * expanded.
626
     * <p>Given all of this, if no context node is set for the evaluation
627
     * of the XPath expression, one must be set so Xalan
628
     * can successfully evaluate a JSTL XPath expression.
629
     * (it will not work if the context node is given as a varialbe
630
     * at the beginning of the expression)
631
     *
632
     * @@@ Provide more details...
633
     */
634
    protected Node adaptParamsForXalan(JstlVariableContext jvc, Node n,
635
                                       String xpath) {
636
        Node boundDocument = null;
637
638
        modifiedXPath = xpath;
639
        String origXPath = xpath;
640
        boolean whetherOrigXPath = true;
641
642
        // If contextNode is not null then  just pass the values to Xalan XPath
643
        // unless this is an expression that starts off with an xml document 
644
        if (n != null && !xpath.startsWith("$")) {
645
            return n;
646
        }
647
648
        if (xpath.startsWith("$")) {
649
            // JSTL uses $scopePrefix:varLocalName/xpath expression
650
651
            String varQName = xpath.substring(xpath.indexOf("$") + 1);
652
            if (varQName.indexOf("/") > 0) {
653
                varQName = varQName.substring(0, varQName.indexOf("/"));
654
            }
655
            String varPrefix = null;
656
            String varLocalName = varQName;
657
            if (varQName.indexOf(":") >= 0) {
658
                varPrefix = varQName.substring(0, varQName.indexOf(":"));
659
                varLocalName = varQName.substring(varQName.indexOf(":") + 1);
660
            }
661
662
            if (xpath.indexOf("/") > 0) {
663
                xpath = xpath.substring(xpath.indexOf("/"));
664
            } else {
665
                xpath = "/*";
666
                whetherOrigXPath = false;
667
            }
668
669
670
            try {
671
                Object varObject = jvc.getVariableValue(null, varPrefix,
672
                        varLocalName);
673
                //System.out.println( "varObject => : its Class " +varObject +
674
                // ":" + varObject.getClass() );
675
676
                if (Class.forName("org.w3c.dom.Document").isInstance(
677
                        varObject)) {
678
                    //boundDocument = ((Document)varObject).getDocumentElement();
679
                    boundDocument = ((Document) varObject);
680
                } else {
681
682
                    //System.out.println("Creating a Dummy document to pass " +
683
                    // " onto as context node " );
684
685
                    if (Class.forName("org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(varObject)) {
686
                        Document newDocument = getDummyDocument();
687
688
                        JSTLNodeList jstlNodeList = (JSTLNodeList) varObject;
689
                        if (jstlNodeList.getLength() == 1) {
690
                            if (Class.forName("org.w3c.dom.Node").isInstance(
691
                                    jstlNodeList.elementAt(0))) {
692
                                Node node = (Node) jstlNodeList.elementAt(0);
693
                                boundDocument = getDocumentForNode(node);
694
                                if (whetherOrigXPath) {
695
                                    xpath = "/*" + xpath;
696
                                }
697
698
                            } else {
699
700
                                //Nodelist with primitive type
701
                                Object myObject = jstlNodeList.elementAt(0);
702
703
                                //p("Single Element of primitive type");
704
                                //p("Type => " + myObject.getClass());
705
706
                                xpath = myObject.toString();
707
708
                                //p("String value ( xpathwould be this) => " + xpath);
709
                                boundDocument = newDocument;
710
                            }
711
712
                        } else {
713
714
                            Element dummyroot = newDocument.getDocumentElement();
715
                            for (int i = 0; i < jstlNodeList.getLength(); i++) {
716
                                Node currNode = (Node) jstlNodeList.item(i);
717
718
                                Node importedNode = newDocument.importNode(
719
                                        currNode, true);
720
721
                                //printDetails ( newDocument);
722
723
                                dummyroot.appendChild(importedNode);
724
725
                                //p( "Details of the document After importing");
726
                                //printDetails ( newDocument);
727
                            }
728
                            boundDocument = newDocument;
729
                            // printDetails ( boundDocument );
730
                            //Verify :As we are adding Document element we need
731
                            // to change the xpath expression.Hopefully this
732
                            // won't  change the result
733
734
                            xpath = "/*" + xpath;
735
                        }
736
                    } else if (Class.forName("org.w3c.dom.Node").isInstance(
737
                            varObject)) {
738
                        boundDocument = getDocumentForNode((Node) varObject);
739
                        if (whetherOrigXPath) {
740
                            xpath = "/*" + xpath;
741
                        }
742
                    } else {
743
                        boundDocument = getDummyDocument();
744
                        xpath = origXPath;
745
                    }
746
747
748
                }
749
            } catch (UnresolvableException ue) {
750
                // TODO: LOG
751
                System.out.println("Variable Unresolvable :" + ue.getMessage());
752
                ue.printStackTrace();
753
            } catch (ClassNotFoundException cnf) {
754
                // Will never happen
755
            }
756
        } else {
757
            //System.out.println("Not encountered $ Creating a Dummydocument 2 "+
758
            //   "pass onto as context node " );
759
            boundDocument = getDummyDocument();
760
        }
761
762
        modifiedXPath = xpath;
763
        //System.out.println("Modified XPath::boundDocument =>" + modifiedXPath +
764
        //    "::" + boundDocument );
765
766
        return boundDocument;
767
    }
768
769
770
    //*********************************************************************
771
    // 
772
773
    /**
774
     * * @@@ why do we have to pass varVector in the varStack first, and then
775
     * to XPath object?
776
     */
777
    private Vector fillVarStack(JstlVariableContext vs, XPathContext xpathSupport)
778
            throws JspTagException {
779
        org.apache.xpath.VariableStack myvs = xpathSupport.getVarStack();
780
        Vector varVector = getVariableQNames();
781
        for (int i = 0; i < varVector.size(); i++) {
782
783
            QName varQName = (QName) varVector.elementAt(i);
784
785
            try {
786
                XObject variableValue = vs.getVariableOrParam(xpathSupport, varQName);
787
                //p("&&&&Variable set to => " + variableValue.toString() );
788
                //p("&&&&Variable type => " + variableValue.getTypeString() );
789
                myvs.setGlobalVariable(i, variableValue);
790
791
            } catch (TransformerException te) {
792
                throw new JspTagException(te.toString(), te);
793
            }
794
795
        }
796
        return varVector;
797
    }
798
799
800
    //*********************************************************************
801
    // Static support for context retrieval from parent <forEach> tag
802
803
    public static Node getContext(Tag t) throws JspTagException {
804
        ForEachTag xt =
805
                (ForEachTag) TagSupport.findAncestorWithClass(
806
                        t, ForEachTag.class);
807
        if (xt == null) {
808
            return null;
809
        } else {
810
            return (xt.getContext());
811
        }
812
    }
813
814
    //*********************************************************************
815
    // Utility methods
816
817
    private static void p(String s) {
818
        System.out.println("[XPathUtil] " + s);
819
    }
820
821
    public static void printDetails(Node n) {
822
        System.out.println("\n\nDetails of Node = > " + n);
823
        System.out.println("Name:Type:Node Value = > " + n.getNodeName() +
824
                ":" + n.getNodeType() + ":" + n.getNodeValue());
825
        System.out.println("Namespace URI : Prefix : localName = > " +
826
                n.getNamespaceURI() + ":" + n.getPrefix() + ":" + n.getLocalName());
827
        System.out.println("\n Node has children => " + n.hasChildNodes());
828
        if (n.hasChildNodes()) {
829
            NodeList nl = n.getChildNodes();
830
            System.out.println("Number of Children => " + nl.getLength());
831
            for (int i = 0; i < nl.getLength(); i++) {
832
                Node childNode = nl.item(i);
833
                printDetails(childNode);
834
            }
835
        }
836
    }
837
}
838
839
class JSTLNodeList extends Vector implements NodeList {
840
841
    Vector nodeVector;
842
843
    public JSTLNodeList(Vector nodeVector) {
844
        this.nodeVector = nodeVector;
845
    }
846
847
    public JSTLNodeList(NodeList nl) {
848
        nodeVector = new Vector();
849
        //System.out.println("[JSTLNodeList] nodelist details");
850
        for (int i = 0; i < nl.getLength(); i++) {
851
            Node currNode = nl.item(i);
852
            //XPathUtil.printDetails ( currNode );
853
            nodeVector.add(i, nl.item(i));
854
        }
855
    }
856
857
    public JSTLNodeList(Node n) {
858
        nodeVector = new Vector();
859
        nodeVector.addElement(n);
860
    }
861
862
863
    public Node item(int index) {
864
        return (Node) nodeVector.elementAt(index);
865
    }
866
867
    @Override
868
    public Object elementAt(int index) {
869
        return nodeVector.elementAt(index);
870
    }
871
872
    @Override
873
    public Object get(int index) {
874
        return nodeVector.get(index);
875
    }
876
877
    public int getLength() {
878
        return nodeVector.size();
879
    }
880
881
    @Override
882
    public int size() {
883
        //System.out.println("JSTL node list size => " + nodeVector.size() );
884
        return nodeVector.size();
885
    }
886
887
    // Can implement other Vector methods to redirect those methods to 
888
    // the vector in the variable param. As we are not using them as part 
889
    // of this implementation we are not doing that here. If this changes
890
    // then we need to override those methods accordingly  
891
892
}
893
         
894
895
896
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java (-51 / +31 lines)
Lines 17-28 Link Here
17
17
18
package org.apache.taglibs.standard.tag.common.xml;
18
package org.apache.taglibs.standard.tag.common.xml;
19
19
20
import java.util.List;
21
22
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.JspTagException;
23
import javax.servlet.jsp.jstl.core.LoopTagSupport;
21
import javax.servlet.jsp.jstl.core.LoopTagSupport;
22
import javax.servlet.jsp.tagext.Tag;
23
import javax.servlet.jsp.tagext.TagSupport;
24
24
25
import org.apache.taglibs.standard.resources.Resources;
25
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
26
import org.apache.taglibs.standard.xpath.JSTLXPathContext;
27
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
28
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
26
29
27
/**
30
/**
28
 * <p>Support for the XML library's &lt;forEach&gt; tag.</p>
31
 * <p>Support for the XML library's &lt;forEach&gt; tag.</p>
Lines 32-91 Link Here
32
 */
35
 */
33
public class ForEachTag extends LoopTagSupport {
36
public class ForEachTag extends LoopTagSupport {
34
37
35
    //*********************************************************************
38
    private JSTLXPathCompiler compiler;
36
    // Private state
39
    private JSTLXPathExpression select;
40
    private JSTLXPathContext context;
37
41
38
    private String select;                // tag attribute
42
    public ForEachTag() {
39
    private List nodes;                    // XPath result
43
        JSTLXPathFactory xpf = JSTLXPathFactory.getFactory();
40
    private int nodesIndex;                // current index
44
        compiler = xpf.newCompiler();
41
    private org.w3c.dom.Node current;            // current node
45
    }
42
46
43
    //*********************************************************************
47
    @Override
44
    // Iteration control methods
48
    public void release() {
49
        super.release();
50
        compiler = null;
51
        select = null;
52
        context = null;
53
    }
45
54
46
    // (We inherit semantics and Javadoc from LoopTagSupport.) 
47
48
    @Override
55
    @Override
49
    protected void prepare() throws JspTagException {
56
    protected void prepare() throws JspTagException {
50
        nodesIndex = 0;
57
        context = select.iterate(getContext(this), pageContext);
51
        XPathUtil xu = new XPathUtil(pageContext);
52
        nodes = xu.selectNodes(XPathUtil.getContext(this), select);
53
    }
58
    }
54
59
55
    @Override
60
    @Override
56
    protected boolean hasNext() throws JspTagException {
61
    protected boolean hasNext() throws JspTagException {
57
        return (nodesIndex < nodes.size());
62
        return context.hasNext();
58
    }
63
    }
59
64
60
    @Override
65
    @Override
61
    protected Object next() throws JspTagException {
66
    protected Object next() throws JspTagException {
62
        Object o = nodes.get(nodesIndex++);
67
        return context.next();
63
        if (!(o instanceof org.w3c.dom.Node)) {
64
            throw new JspTagException(
65
                    Resources.getMessage("FOREACH_NOT_NODESET"));
66
        }
67
        current = (org.w3c.dom.Node) o;
68
        return current;
69
    }
68
    }
70
69
71
70
72
    //*********************************************************************
71
    //*********************************************************************
73
    // Tag logic and lifecycle management
74
75
    // Releases any resources we may have (or inherit)
76
77
    @Override
78
    public void release() {
79
        init();
80
        super.release();
81
    }
82
83
84
    //*********************************************************************
85
    // Attribute accessors
72
    // Attribute accessors
86
73
87
    public void setSelect(String select) {
74
    public void setSelect(String select) {
88
        this.select = select;
75
        this.select = compiler.compile(select);
89
    }
76
    }
90
77
91
    public void setBegin(int begin) throws JspTagException {
78
    public void setBegin(int begin) throws JspTagException {
Lines 111-130 Link Here
111
98
112
    /* Retrieves the current context. */
99
    /* Retrieves the current context. */
113
100
114
    public org.w3c.dom.Node getContext() throws JspTagException {
101
    public static JSTLXPathContext getContext(Tag child) {
115
        // expose the current node as the context
102
        ForEachTag forEachTag = (ForEachTag) TagSupport.findAncestorWithClass(child, ForEachTag.class);
116
        return current;
103
        if (forEachTag == null) {
104
            return null;
105
        } else {
106
            return forEachTag.context;
107
        }
117
    }
108
    }
118
119
120
    //*********************************************************************
121
    // Private utility methods
122
123
    private void init() {
124
        select = null;
125
        nodes = null;
126
        nodesIndex = 0;
127
        current = null;
128
    }
129
}
109
}
130
110
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/SetTag.java (-43 / +17 lines)
Lines 17-29 Link Here
17
17
18
package org.apache.taglibs.standard.tag.common.xml;
18
package org.apache.taglibs.standard.tag.common.xml;
19
19
20
import java.util.List;
21
22
import javax.servlet.jsp.JspException;
20
import javax.servlet.jsp.JspException;
23
import javax.servlet.jsp.PageContext;
21
import javax.servlet.jsp.PageContext;
24
import javax.servlet.jsp.tagext.TagSupport;
22
import javax.servlet.jsp.tagext.TagSupport;
25
23
26
import org.apache.taglibs.standard.tag.common.core.Util;
24
import org.apache.taglibs.standard.tag.common.core.Util;
25
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
26
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
27
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
27
28
28
/**
29
/**
29
 * <p>Tag handler for &lt;set&gt; in JSTL's XML library.</p>
30
 * <p>Tag handler for &lt;set&gt; in JSTL's XML library.</p>
Lines 32-44 Link Here
32
 */
33
 */
33
public class SetTag extends TagSupport {
34
public class SetTag extends TagSupport {
34
35
35
    //*********************************************************************
36
    private JSTLXPathCompiler compiler;
36
    // Internal state
37
    private JSTLXPathExpression select;
38
    private String var;
39
    private int scope = PageContext.PAGE_SCOPE;
37
40
38
    private String select;                    // tag attribute
39
    private String var;                       // tag attribute
40
    private int scope;                  // processed tag attribute
41
42
    //*********************************************************************
41
    //*********************************************************************
43
    // Construction and initialization
42
    // Construction and initialization
44
43
Lines 48-66 Link Here
48
     * superclass constructor.
47
     * superclass constructor.
49
     */
48
     */
50
    public SetTag() {
49
    public SetTag() {
51
        super();
50
        JSTLXPathFactory xpf = JSTLXPathFactory.getFactory();
52
        init();
51
        compiler = xpf.newCompiler();
53
    }
52
    }
54
53
55
    // resets local state
54
    @Override
56
55
    public void release() {
57
    private void init() {
56
        super.release();
58
        var = null;
57
        compiler = null;
59
        select = null;
58
        select = null;
60
        scope = PageContext.PAGE_SCOPE;
59
        var = null;
61
    }
60
    }
62
61
63
64
    //*********************************************************************
62
    //*********************************************************************
65
    // Tag logic
63
    // Tag logic
66
64
Lines 68-107 Link Here
68
66
69
    @Override
67
    @Override
70
    public int doStartTag() throws JspException {
68
    public int doStartTag() throws JspException {
71
        // process the query
69
        Object result = select.evaluateObject(ForEachTag.getContext(this), pageContext);
72
        XPathUtil xu = new XPathUtil(pageContext);
70
        pageContext.setAttribute(var, result, scope);
73
        List result =
74
                xu.selectNodes(XPathUtil.getContext(this), select);
75
        Object ret = result;
76
77
        // unwrap primitive types if that's what we received
78
        if (result.size() == 1) {
79
            Object o = result.get(0);
80
            if (o instanceof String || o instanceof Boolean
81
                    || o instanceof Number) {
82
                ret = o;
83
            }
84
        }
85
86
        // expose the final result
87
        pageContext.setAttribute(var, ret, scope);
88
        return SKIP_BODY;
71
        return SKIP_BODY;
89
    }
72
    }
90
73
91
    // Releases any resources we may have (or inherit)
92
93
    @Override
94
    public void release() {
95
        super.release();
96
        init();
97
    }
98
99
100
    //*********************************************************************
74
    //*********************************************************************
101
    // Attribute accessors
75
    // Attribute accessors
102
76
103
    public void setSelect(String select) {
77
    public void setSelect(String select) {
104
        this.select = select;
78
        this.select = compiler.compile(select);
105
    }
79
    }
106
80
107
    public void setVar(String var) {
81
    public void setVar(String var) {
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/IfTag.java (-36 / +12 lines)
Lines 20-25 Link Here
20
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.JspTagException;
21
import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
21
import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
22
22
23
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
24
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
25
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
26
23
/**
27
/**
24
 * <p>Tag handler for &lt;if&gt; in JSTL's XML library.</p>
28
 * <p>Tag handler for &lt;if&gt; in JSTL's XML library.</p>
25
 *
29
 *
Lines 28-82 Link Here
28
32
29
public class IfTag extends ConditionalTagSupport {
33
public class IfTag extends ConditionalTagSupport {
30
34
31
    //*********************************************************************
35
    private JSTLXPathCompiler compiler;
32
    // Constructor and lifecycle management
36
    private JSTLXPathExpression select;
33
37
34
    // initialize inherited and local state
35
36
    public IfTag() {
38
    public IfTag() {
37
        super();
39
        JSTLXPathFactory xpf = JSTLXPathFactory.getFactory();
38
        init();
40
        compiler = xpf.newCompiler();
39
    }
41
    }
40
42
41
    // Releases any resources we may have (or inherit)
42
43
    @Override
43
    @Override
44
    public void release() {
44
    public void release() {
45
        super.release();
45
        super.release();
46
        init();
46
        compiler = null;
47
        select = null;
47
    }
48
    }
48
49
49
50
    //*********************************************************************
51
    // Supplied conditional logic
52
53
    @Override
50
    @Override
54
    protected boolean condition() throws JspTagException {
51
    protected boolean condition() throws JspTagException {
55
        XPathUtil xu = new XPathUtil(pageContext);
52
        return select.evaluateBoolean(ForEachTag.getContext(this), pageContext);
56
        return (xu.booleanValueOf(XPathUtil.getContext(this), select));
57
    }
53
    }
58
54
59
60
    //*********************************************************************
61
    // Private state
62
63
    private String select;               // the value of the 'test' attribute
64
65
66
    //*********************************************************************
67
    // Attribute accessors
68
69
    public void setSelect(String select) {
55
    public void setSelect(String select) {
70
        this.select = select;
56
        this.select = compiler.compile(select);
71
    }
57
    }
72
73
74
    //*********************************************************************
75
    // Private utility methods
76
77
    // resets internal state
78
79
    private void init() {
80
        select = null;
81
    }
82
}
58
}
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java (-40 / +18 lines)
Lines 5-13 Link Here
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Lines 22-73 Link Here
22
import javax.servlet.jsp.tagext.TagSupport;
22
import javax.servlet.jsp.tagext.TagSupport;
23
23
24
import org.apache.taglibs.standard.util.EscapeXML;
24
import org.apache.taglibs.standard.util.EscapeXML;
25
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
26
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
27
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
25
28
26
/**
29
/**
27
 * <p>Tag handler for &lt;out&gt; in JSTL's XML library.</p>
30
 * Tag handler for &lt;out&gt; in JSTL's XML library.
28
 * <p>TODO: should we rename this to OutSupport to match the tag name?
31
 * TODO: should we rename this to OutSupport to match the tag name?
29
 *
32
 *
30
 * @author Shawn Bayern
33
 * @author Shawn Bayern
31
 */
34
 */
32
public abstract class ExprSupport extends TagSupport {
35
public abstract class ExprSupport extends TagSupport {
33
36
34
    //*********************************************************************
37
    private JSTLXPathCompiler compiler;
35
    // Internal state
38
    private JSTLXPathExpression select;
39
    protected boolean escapeXml = true;  // tag attribute
36
40
37
    private String select;                       // tag attribute
38
    protected boolean escapeXml;         // tag attribute
39
40
    //*********************************************************************
41
    // Construction and initialization
42
43
    /**
44
     * Constructs a new handler.  As with TagSupport, subclasses should
45
     * not provide other constructors and are expected to call the
46
     * superclass constructor.
47
     */
48
    public ExprSupport() {
41
    public ExprSupport() {
49
        super();
42
        JSTLXPathFactory xpf = JSTLXPathFactory.getFactory();
50
        init();
43
        compiler = xpf.newCompiler();
51
    }
44
    }
52
45
53
    // resets local state
46
    @Override
54
47
    public void release() {
55
    private void init() {
48
        super.release();
49
        compiler = null;
56
        select = null;
50
        select = null;
57
        escapeXml = true;
58
    }
51
    }
59
52
60
61
    //*********************************************************************
53
    //*********************************************************************
62
    // Tag logic
54
    // Tag logic
63
55
64
    // applies XPath expression from 'select' and prints the result
56
    // applies XPath expression from 'select' and prints the result
65
66
    @Override
57
    @Override
67
    public int doStartTag() throws JspException {
58
    public int doStartTag() throws JspException {
68
        try {
59
        try {
69
            XPathUtil xu = new XPathUtil(pageContext);
60
            String result = select.evaluateString(ForEachTag.getContext(this), pageContext);
70
            String result = xu.valueOf(XPathUtil.getContext(this), select);
71
            EscapeXML.emit(result, escapeXml, pageContext.getOut());
61
            EscapeXML.emit(result, escapeXml, pageContext.getOut());
72
            return SKIP_BODY;
62
            return SKIP_BODY;
73
        } catch (java.io.IOException ex) {
63
        } catch (java.io.IOException ex) {
Lines 75-93 Link Here
75
        }
65
        }
76
    }
66
    }
77
67
78
    // Releases any resources we may have (or inherit)
79
80
    @Override
81
    public void release() {
82
        super.release();
83
        init();
84
    }
85
86
87
    //*********************************************************************
88
    // Attribute accessors
89
90
    public void setSelect(String select) {
68
    public void setSelect(String select) {
91
        this.select = select;
69
        this.select = compiler.compile(select);
92
    }
70
    }
93
}
71
}
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java (-296 lines)
Lines 1-296 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
package org.apache.taglibs.standard.tag.common.xml;
19
20
import java.util.Vector;
21
22
import javax.servlet.jsp.JspTagException;
23
import javax.xml.transform.TransformerException;
24
25
import org.apache.taglibs.standard.resources.Resources;
26
import org.apache.xml.utils.PrefixResolver;
27
import org.apache.xpath.XPath;
28
import org.apache.xpath.XPathAPI;
29
import org.apache.xpath.XPathContext;
30
import org.apache.xpath.objects.XObject;
31
import org.w3c.dom.Node;
32
import org.w3c.dom.NodeList;
33
import org.w3c.dom.traversal.NodeIterator;
34
35
/**
36
 * The methods in this class are convenience methods into the
37
 * low-level XPath API.
38
 * These functions tend to be a little slow, since a number of objects must be
39
 * created for each evaluation.  A faster way is to precompile the
40
 * XPaths using the low-level API, and then just use the XPaths
41
 * over and over.
42
 * <p>NOTE: In particular, each call to this method will create a new
43
 * XPathContext, a new DTMManager... and thus a new DTM. That's very
44
 * safe, since it guarantees that you're always processing against a
45
 * fully up-to-date view of your document. But it's also portentially
46
 * very expensive, since you're rebuilding the DTM every time. You should
47
 * consider using an instance of CachedXPathAPI rather than these static
48
 * methods.
49
 *
50
 * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a>
51
 */
52
public class JSTLXPathAPI extends XPathAPI {
53
    /**
54
     * Use an XPath string to select a single node.
55
     * XPath namespace prefixes are resolved using the prefixResolver.
56
     *
57
     * @param contextNode    The node to start searching from.
58
     * @param str            A valid XPath string.
59
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
60
     * @return The first node found that matches the XPath, or null.
61
     * @throws JspTagException
62
     */
63
    public static Node selectSingleNode(
64
            Node contextNode, String str, PrefixResolver prefixResolver)
65
            throws JspTagException {
66
67
        // Have the XObject return its result as a NodeSetDTM.
68
        NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver);
69
70
        // Return the first node, or null
71
        return nl.nextNode();
72
    }
73
74
    /**
75
     * Use an XPath string to select a single node.
76
     * XPath namespace prefixes are resolved using the prefixResolver.
77
     *
78
     * @param contextNode    The node to start searching from.
79
     * @param str            A valid XPath string.
80
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
81
     * @return The first node found that matches the XPath, or null.
82
     * @throws JspTagException
83
     */
84
    public static Node selectSingleNode(
85
            Node contextNode, String str, PrefixResolver prefixResolver,
86
            XPathContext xpathSupport) throws JspTagException {
87
88
        // Have the XObject return its result as a NodeSetDTM.
89
        NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver, xpathSupport);
90
91
        // Return the first node, or null
92
        return nl.nextNode();
93
    }
94
95
    /**
96
     * Use an XPath string to select a nodelist.
97
     * XPath namespace prefixes are resolved using PrefixResolver.
98
     *
99
     * @param contextNode    The node to start searching from.
100
     * @param str            A valid XPath string.
101
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
102
     * @return A NodeIterator, should never be null.
103
     * @throws JspTagException
104
     */
105
    public static NodeIterator selectNodeIterator(
106
            Node contextNode, String str, PrefixResolver prefixResolver)
107
            throws JspTagException {
108
109
        // Execute the XPath, and have it return the result
110
        XObject list = eval(contextNode, str, prefixResolver, null);
111
112
        // Have the XObject return its result as a NodeSetDTM.
113
        return getNodeIterator(list);
114
    }
115
116
    /**
117
     * Use an XPath string to select a nodelist.
118
     * XPath namespace prefixes are resolved using PrefixResolver.
119
     *
120
     * @param contextNode    The node to start searching from.
121
     * @param str            A valid XPath string.
122
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
123
     * @return A NodeIterator, should never be null.
124
     * @throws JspTagException
125
     */
126
    public static NodeIterator selectNodeIterator(
127
            Node contextNode, String str, PrefixResolver prefixResolver,
128
            XPathContext xpathSupport) throws JspTagException {
129
130
        // Execute the XPath, and have it return the result
131
        XObject list = eval(contextNode, str, prefixResolver, xpathSupport);
132
133
        // Have the XObject return its result as a NodeSetDTM.
134
        return getNodeIterator(list);
135
    }
136
137
    /**
138
     * Use an XPath string to select a nodelist.
139
     * XPath namespace prefixes are resolved using the prefixResolver.
140
     *
141
     * @param contextNode    The node to start searching from.
142
     * @param str            A valid XPath string.
143
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
144
     * @return A NodeIterator, should never be null.
145
     * @throws JspTagException
146
     */
147
    private static NodeList selectNodeList(
148
            Node contextNode, String str, PrefixResolver prefixResolver)
149
            throws JspTagException {
150
        // Execute the XPath, and have it return the result
151
        XObject list = eval(contextNode, str, prefixResolver, null);
152
153
        // Return a NodeList.
154
        return getNodeList(list);
155
    }
156
157
    /**
158
     * Use an XPath string to select a nodelist.
159
     * XPath namespace prefixes are resolved using the prefixResolver.
160
     *
161
     * @param contextNode    The node to start searching from.
162
     * @param str            A valid XPath string.
163
     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
164
     * @return A NodeIterator, should never be null.
165
     * @throws JspTagException
166
     */
167
    public static NodeList selectNodeList(
168
            Node contextNode, String str, PrefixResolver prefixResolver,
169
            XPathContext xpathSupport)
170
            throws JspTagException {
171
        // Execute the XPath, and have it return the result
172
        XObject list = eval(contextNode, str, prefixResolver, xpathSupport);
173
174
        // Return a NodeList.
175
        return getNodeList(list);
176
    }
177
178
    /**
179
     * Returns a NodeIterator from an XObject.
180
     *
181
     * @param list The XObject from which a NodeIterator is returned.
182
     * @return A NodeIterator, should never be null.
183
     * @throws JspTagException
184
     */
185
    private static NodeIterator getNodeIterator(XObject list)
186
            throws JspTagException {
187
        try {
188
            return list.nodeset();
189
        } catch (TransformerException ex) {
190
            throw new JspTagException(
191
                    Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);
192
        }
193
    }
194
195
    /**
196
     * Returns a NodeList from an XObject.
197
     *
198
     * @param list The XObject from which a NodeList is returned.
199
     * @return A NodeList, should never be null.
200
     * @throws JspTagException
201
     */
202
    static NodeList getNodeList(XObject list)
203
            throws JspTagException {
204
        try {
205
            return list.nodelist();
206
        } catch (TransformerException ex) {
207
            throw new JspTagException(
208
                    Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);
209
        }
210
    }
211
212
    /**
213
     * Evaluate XPath string to an XObject.
214
     * XPath namespace prefixes are resolved from the namespaceNode.
215
     * The implementation of this is a little slow, since it creates
216
     * a number of objects each time it is called.  This could be optimized
217
     * to keep the same objects around, but then thread-safety issues would arise.
218
     *
219
     * @param contextNode    The node to start searching from.
220
     * @param str            A valid XPath string.
221
     * @param xpathSupport   The node from which prefixes in the XPath will be resolved to namespaces.
222
     * @param prefixResolver Will be called if the parser encounters namespace
223
     *                       prefixes, to resolve the prefixes to URLs.
224
     * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
225
     * @throws JspTagException
226
     * @see org.apache.xpath.objects.XObject
227
     * @see org.apache.xpath.objects.XNull
228
     * @see org.apache.xpath.objects.XBoolean
229
     * @see org.apache.xpath.objects.XNumber
230
     * @see org.apache.xpath.objects.XString
231
     * @see org.apache.xpath.objects.XRTreeFrag
232
     */
233
    public static XObject eval(
234
            Node contextNode, String str, PrefixResolver prefixResolver,
235
            XPathContext xpathSupport) throws JspTagException {
236
        //System.out.println("eval of XPathContext params: contextNode:str(xpath)"+
237
        // ":prefixResolver:xpathSupport => " + contextNode + ":" + str + ":" +
238
        //  prefixResolver + ":" + xpathSupport );        
239
        try {
240
            if (xpathSupport == null) {
241
                return eval(contextNode, str, prefixResolver);
242
            }
243
244
            // Since we don't have a XML Parser involved here, install some default support
245
            // for things like namespaces, etc.
246
            // (Changed from: XPathContext xpathSupport = new XPathContext();
247
            //    because XPathContext is weak in a number of areas... perhaps
248
            //    XPathContext should be done away with.)
249
            // Create the XPath object.
250
            XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
251
252
            // Execute the XPath, and have it return the result
253
            int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
254
255
            // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode );
256
            XObject xobj = xpath.execute(xpathSupport, ctxtNode, prefixResolver);
257
            return xobj;
258
        } catch (TransformerException ex) {
259
            throw new JspTagException(
260
                    Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex);
261
        } catch (IllegalArgumentException ex) {
262
            throw new JspTagException(
263
                    Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex);
264
        }
265
    }
266
267
    public static XObject eval(
268
            Node contextNode, String str, PrefixResolver prefixResolver,
269
            XPathContext xpathSupport, Vector varQNames) throws JspTagException {
270
        //p("***************** eval ");
271
        //p( "contextNode => " + contextNode );
272
        //p( "XPath str => " + str );
273
        //p( "PrefixResolver => " + prefixResolver );
274
        //p( "XPath Context => " + xpathSupport );
275
        //p( "Var QNames => " + varQNames );
276
        //p( "Global Var Size => " + varQNames.size() );        
277
        try {
278
            XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
279
            xpath.fixupVariables(varQNames, varQNames.size());
280
            // Execute the XPath, and have it return the result
281
            int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
282
            // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode );            
283
            return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
284
        } catch (TransformerException ex) {
285
            throw new JspTagException(
286
                    Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex);
287
        } catch (IllegalArgumentException ex) {
288
            throw new JspTagException(
289
                    Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex);
290
        }
291
    }
292
293
    private static void p(String s) {
294
        System.out.println("[JSTLXPathAPI] " + s);
295
    }
296
}
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java (-145 lines)
Lines 1-145 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.tag.common.xml;
18
19
import java.util.HashMap;
20
21
import org.apache.xml.utils.PrefixResolver;
22
import org.w3c.dom.NamedNodeMap;
23
import org.w3c.dom.Node;
24
25
/**
26
 * <meta name="usage" content="general"/>
27
 * This class implements a JSTL PrefixResolver that
28
 * can be used to perform prefix-to-namespace lookup
29
 * for the XPath object.
30
 */
31
public class JSTLPrefixResolver implements PrefixResolver {
32
33
    /**
34
     * The context to resolve the prefix from, if the context
35
     * is not given.
36
     */
37
38
    HashMap namespaces;
39
40
    /**
41
     * The URI for the XML namespace.
42
     * (Duplicate of that found in org.apache.xpath.XPathContext).
43
     */
44
45
    public static final String S_XMLNAMESPACEURI =
46
            "http://www.w3.org/XML/1998/namespace";
47
48
    /**
49
     * No-arg constructor which would create empty HashMap of namespaces
50
     */
51
    public JSTLPrefixResolver() {
52
        namespaces = new HashMap();
53
    }
54
55
    public JSTLPrefixResolver(HashMap nses) {
56
        namespaces = nses;
57
    }
58
59
    /**
60
     * Given a namespace, get the corresponding prefix.  This assumes that
61
     * the PrevixResolver hold's it's own namespace context, or is a namespace
62
     * context itself.
63
     *
64
     * @param prefix Prefix to resolve.
65
     * @return Namespace that prefix resolves to, or null if prefix
66
     *         is not bound.
67
     */
68
    public String getNamespaceForPrefix(String prefix) {
69
        return (String) namespaces.get(prefix);
70
    }
71
72
    /**
73
     * Given a prefix and a Context Node, get the corresponding namespace.
74
     * Warning: This will not work correctly if namespaceContext
75
     * is an attribute node.
76
     *
77
     * @param prefix           Prefix to resolve.
78
     * @param namespaceContext Node from which to start searching for a
79
     *                         xmlns attribute that binds a prefix to a namespace.
80
     * @return Namespace that prefix resolves to, or null if prefix
81
     *         is not bound.
82
     */
83
    public String getNamespaceForPrefix(String prefix,
84
                                        org.w3c.dom.Node namespaceContext) {
85
86
        Node parent = namespaceContext;
87
        String namespace = null;
88
89
        if (prefix.equals("xml")) {
90
            namespace = S_XMLNAMESPACEURI;
91
        } else {
92
            int type;
93
94
            while ((null != parent) && (null == namespace)
95
                    && (((type = parent.getNodeType()) == Node.ELEMENT_NODE)
96
                    || (type == Node.ENTITY_REFERENCE_NODE))) {
97
                if (type == Node.ELEMENT_NODE) {
98
                    NamedNodeMap nnm = parent.getAttributes();
99
100
                    for (int i = 0; i < nnm.getLength(); i++) {
101
                        Node attr = nnm.item(i);
102
                        String aname = attr.getNodeName();
103
                        boolean isPrefix = aname.startsWith("xmlns:");
104
105
                        if (isPrefix || aname.equals("xmlns")) {
106
                            int index = aname.indexOf(':');
107
                            String p = isPrefix ? aname.substring(index + 1) : "";
108
109
                            if (p.equals(prefix)) {
110
                                namespace = attr.getNodeValue();
111
112
                                break;
113
                            }
114
                        }
115
                    }
116
                }
117
118
                parent = parent.getParentNode();
119
            }
120
        }
121
122
        return namespace;
123
    }
124
125
    /**
126
     * Return the base identifier.
127
     *
128
     * @return null
129
     */
130
    public String getBaseIdentifier() {
131
        return null;
132
    }
133
134
    /**
135
     * @see PrefixResolver#handlesNullPrefixes()
136
     */
137
    public boolean handlesNullPrefixes() {
138
        return false;
139
    }
140
141
    public void addNamespace(String prefix, String uri) {
142
        namespaces.put(prefix, uri);
143
    }
144
145
}
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/WhenTag.java (-35 / +11 lines)
Lines 20-25 Link Here
20
import javax.servlet.jsp.JspTagException;
20
import javax.servlet.jsp.JspTagException;
21
21
22
import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
22
import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
23
import org.apache.taglibs.standard.xpath.JSTLXPathCompiler;
24
import org.apache.taglibs.standard.xpath.JSTLXPathExpression;
25
import org.apache.taglibs.standard.xpath.JSTLXPathFactory;
23
26
24
/**
27
/**
25
 * <p>Tag handler for &lt;if&gt; in JSTL's XML library.</p>
28
 * <p>Tag handler for &lt;if&gt; in JSTL's XML library.</p>
Lines 29-82 Link Here
29
32
30
public class WhenTag extends WhenTagSupport {
33
public class WhenTag extends WhenTagSupport {
31
34
32
    //*********************************************************************
35
    private JSTLXPathCompiler compiler;
33
    // Constructor and lifecycle management
36
    private JSTLXPathExpression select;
34
37
35
    // initialize inherited and local state
36
37
    public WhenTag() {
38
    public WhenTag() {
38
        super();
39
        JSTLXPathFactory xpf = JSTLXPathFactory.getFactory();
39
        init();
40
        compiler = xpf.newCompiler();
40
    }
41
    }
41
42
42
    // Releases any resources we may have (or inherit)
43
44
    @Override
43
    @Override
45
    public void release() {
44
    public void release() {
46
        super.release();
45
        super.release();
47
        init();
46
        compiler = null;
47
        select = null;
48
    }
48
    }
49
49
50
51
    //*********************************************************************
52
    // Supplied conditional logic
53
54
    @Override
50
    @Override
55
    protected boolean condition() throws JspTagException {
51
    protected boolean condition() throws JspTagException {
56
        XPathUtil xu = new XPathUtil(pageContext);
52
        return select.evaluateBoolean(ForEachTag.getContext(this), pageContext);
57
        return (xu.booleanValueOf(XPathUtil.getContext(this), select));
58
    }
53
    }
59
54
60
    //*********************************************************************
61
    // Private state
62
63
    private String select;               // the value of the 'test' attribute
64
65
66
    //*********************************************************************
67
    // Attribute accessors
68
69
    public void setSelect(String select) {
55
    public void setSelect(String select) {
70
        this.select = select;
56
        this.select = compiler.compile(select);
71
    }
57
    }
72
73
74
    //*********************************************************************
75
    // Private utility methods
76
77
    // resets internal state
78
79
    private void init() {
80
        select = null;
81
    }
82
}
58
}

Return to bug 27717