KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > standard > tag > common > xml > XPathUtil


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.taglibs.standard.tag.common.xml;
18
19 import java.util.Enumeration JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Vector JavaDoc;
23
24 import javax.servlet.http.Cookie JavaDoc;
25 import javax.servlet.http.HttpServletRequest JavaDoc;
26 import javax.servlet.jsp.JspTagException JavaDoc;
27 import javax.servlet.jsp.PageContext JavaDoc;
28 import javax.servlet.jsp.tagext.Tag JavaDoc;
29 import javax.servlet.jsp.tagext.TagSupport JavaDoc;
30 import javax.xml.parsers.DocumentBuilder JavaDoc;
31 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
32 import javax.xml.transform.TransformerException JavaDoc;
33
34 import org.apache.taglibs.standard.resources.Resources;
35 import org.apache.xml.utils.QName;
36 import org.apache.xpath.VariableStack;
37 import org.apache.xpath.XPathContext;
38 import org.apache.xpath.objects.XBoolean;
39 import org.apache.xpath.objects.XNodeSetForDOM;
40 import org.apache.xpath.objects.XNumber;
41 import org.apache.xpath.objects.XObject;
42 import org.apache.xpath.objects.XString;
43 import org.w3c.dom.DOMImplementation JavaDoc;
44 import org.w3c.dom.Document JavaDoc;
45 import org.w3c.dom.Element JavaDoc;
46 import org.w3c.dom.Node JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48
49 /**
50  * <p>Support for tag handlers that evaluate XPath expressions.</p>
51  *
52  * @author Shawn Bayern
53  * @author Ramesh Mandava ( ramesh.mandava@sun.com )
54  * @author Pierre Delisle ( pierre.delisle@sun.com )
55  */

56 // would ideally be a base class, but some of our user handlers already
57
// have their own parents
58
public class XPathUtil {
59     
60     //*********************************************************************
61
// Constructor
62

63     /**
64      * Constructs a new XPathUtil object associated with the given
65      * PageContext.
66      */

67     public XPathUtil(PageContext JavaDoc pc) {
68         pageContext = pc;
69     }
70     
71     int globalVarSize=0;
72     public Vector JavaDoc getVariableQNames ( ) {
73
74         globalVarSize = 0;
75         Vector JavaDoc variableVector = new Vector JavaDoc ( );
76         // Now construct attributes in different scopes
77
Enumeration JavaDoc enum_ = pageContext.getAttributeNamesInScope(
78             PageContext.PAGE_SCOPE );
79         while ( enum_.hasMoreElements() ) {
80             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
81             QName varQName = new QName ( PAGE_NS_URL, PAGE_P, varName);
82             //Adding both namespace qualified QName and just localName
83
variableVector.addElement( varQName );
84             globalVarSize++;
85             
86             variableVector.addElement( new QName(null, varName ) );
87             globalVarSize++;
88         }
89         enum_ = pageContext.getAttributeNamesInScope(
90             PageContext.REQUEST_SCOPE );
91         while ( enum_.hasMoreElements() ) {
92             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
93             QName varQName = new QName ( REQUEST_NS_URL,REQUEST_P, varName);
94             //Adding both namespace qualified QName and just localName
95
variableVector.addElement( varQName );
96             globalVarSize++;
97             variableVector.addElement( new QName(null, varName ) );
98             globalVarSize++;
99         }
100         enum_ = pageContext.getAttributeNamesInScope(
101             PageContext.SESSION_SCOPE );
102         while ( enum_.hasMoreElements() ) {
103             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
104             QName varQName = new QName ( SESSION_NS_URL, SESSION_P,varName);
105             //Adding both namespace qualified QName and just localName
106
variableVector.addElement( varQName );
107             globalVarSize++;
108             variableVector.addElement( new QName(null, varName ) );
109             globalVarSize++;
110         }
111         enum_ = pageContext.getAttributeNamesInScope(
112             PageContext.APPLICATION_SCOPE );
113         while ( enum_.hasMoreElements() ) {
114             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
115             QName varQName = new QName ( APP_NS_URL, APP_P,varName );
116             //Adding both namespace qualified QName and just localName
117
variableVector.addElement( varQName );
118             globalVarSize++;
119             variableVector.addElement( new QName(null, varName ) );
120             globalVarSize++;
121         }
122         enum_ = pageContext.getRequest().getParameterNames();
123         while ( enum_.hasMoreElements() ) {
124             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
125             QName varQName = new QName ( PARAM_NS_URL, PARAM_P,varName );
126             //Adding both namespace qualified QName and just localName
127
variableVector.addElement( varQName );
128             globalVarSize++;
129         }
130         enum_ = pageContext.getServletContext().getInitParameterNames();
131         while ( enum_.hasMoreElements() ) {
132             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
133             QName varQName = new QName ( INITPARAM_NS_URL, INITPARAM_P,varName );
134             //Adding both namespace qualified QName and just localName
135
variableVector.addElement( varQName );
136             globalVarSize++;
137         }
138         enum_ = ((HttpServletRequest JavaDoc)pageContext.getRequest()).getHeaderNames();
139         while ( enum_.hasMoreElements() ) {
140             String JavaDoc varName = (String JavaDoc)enum_.nextElement();
141             QName varQName = new QName ( HEADER_NS_URL, HEADER_P,varName );
142             //Adding namespace qualified QName
143
variableVector.addElement( varQName );
144             globalVarSize++;
145         }
146         Cookie JavaDoc[] c= ((HttpServletRequest JavaDoc)pageContext.getRequest()).getCookies();
147         if ( c!= null ) {
148         for (int i = 0; i < c.length; i++) {
149             String JavaDoc varName = c[i].getName();
150                 QName varQName = new QName ( COOKIE_NS_URL, COOKIE_P,varName );
151                 //Adding namespace qualified QName
152
variableVector.addElement( varQName );
153                 globalVarSize++;
154             }
155         }
156
157         return variableVector;
158         
159     }
160  
161     //*********************************************************************
162
// Support for JSTL variable resolution
163

164     // The URLs
165
private static final String JavaDoc PAGE_NS_URL
166     = "http://java.sun.com/jstl/xpath/page";
167     private static final String JavaDoc REQUEST_NS_URL
168     = "http://java.sun.com/jstl/xpath/request";
169     private static final String JavaDoc SESSION_NS_URL
170     = "http://java.sun.com/jstl/xpath/session";
171     private static final String JavaDoc APP_NS_URL
172     = "http://java.sun.com/jstl/xpath/app";
173     private static final String JavaDoc PARAM_NS_URL
174     = "http://java.sun.com/jstl/xpath/param";
175     private static final String JavaDoc INITPARAM_NS_URL
176     = "http://java.sun.com/jstl/xpath/initParam";
177     private static final String JavaDoc COOKIE_NS_URL
178     = "http://java.sun.com/jstl/xpath/cookie";
179     private static final String JavaDoc HEADER_NS_URL
180     = "http://java.sun.com/jstl/xpath/header";
181     
182     // The prefixes
183
private static final String JavaDoc PAGE_P = "pageScope";
184     private static final String JavaDoc REQUEST_P = "requestScope";
185     private static final String JavaDoc SESSION_P = "sessionScope";
186     private static final String JavaDoc APP_P = "applicationScope";
187     private static final String JavaDoc PARAM_P = "param";
188     private static final String JavaDoc INITPARAM_P = "initParam";
189     private static final String JavaDoc COOKIE_P = "cookie";
190     private static final String JavaDoc HEADER_P = "header";
191     
192     /**
193      * org.apache.xpath.VariableStack defines a class to keep track of a stack
194      * for template arguments and variables.
195      * JstlVariableContext customizes it so it handles JSTL custom
196      * variable-mapping rules.
197      */

198     protected class JstlVariableContext extends org.apache.xpath.VariableStack {
199         
200         public JstlVariableContext( ) {
201             super();
202         }
203         
204         /**
205          * Get a variable as an XPath object based on it's qualified name.
206          * We override the base class method so JSTL's custom variable-mapping
207          * rules can be applied.
208          *
209          * @param xctxt The XPath context. @@@ we don't use it...
210          * (from xalan: which must be passed in order to lazy evaluate variables.)
211          * @param qname The qualified name of the variable.
212          */

213         public XObject getVariableOrParam(
214         XPathContext xctxt,
215         org.apache.xml.utils.QName qname)
216         throws javax.xml.transform.TransformerException JavaDoc, UnresolvableException
217         {
218             //p( "***********************************getVariableOrParam begin****");
219
String JavaDoc namespace = qname.getNamespaceURI();
220             String JavaDoc prefix = qname.getPrefix();
221             String JavaDoc localName = qname.getLocalName();
222             
223             //p("namespace:prefix:localname=>"+ namespace
224
// + ":" + prefix +":" + localName );
225

226             try {
227                 Object JavaDoc varObject = getVariableValue(namespace,prefix,localName);
228
229
230                 //XObject varObject = myvs.getVariableOrParam( xpathSupport, varQName);
231
XObject newXObject = new XObject( varObject);
232
233                 if ( Class.forName("org.w3c.dom.Document").isInstance( varObject) ) {
234
235                     NodeList JavaDoc nl= ((Document JavaDoc)varObject).getChildNodes();
236                     // To allow non-welformed document
237
Vector JavaDoc nodeVector = new Vector JavaDoc();
238                     for ( int i=0; i<nl.getLength(); i++ ) {
239                         Node JavaDoc currNode = nl.item(i);
240                         if ( currNode.getNodeType() == Node.ELEMENT_NODE ) {
241                             nodeVector.addElement( currNode);
242                         }
243                     }
244                     JSTLNodeList jstlNodeList = new JSTLNodeList( nodeVector);
245                     newXObject = new XNodeSetForDOM( jstlNodeList, xctxt );
246                     
247                     return newXObject;
248                    
249                 }
250                 if ( Class.forName(
251         "org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(
252                      varObject) ) {
253                     JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
254                     if ( ( jstlNodeList.getLength() == 1 ) &&
255    (!Class.forName("org.w3c.dom.Node").isInstance( jstlNodeList.elementAt(0) ) ) ) {
256                         varObject = jstlNodeList.elementAt(0);
257                         //Now we need to allow this primitive type to be coverted
258
// to type which Xalan XPath understands
259
} else {
260                         return new XNodeSetForDOM ( jstlNodeList ,xctxt );
261                     }
262                 }
263                 if (Class.forName("org.w3c.dom.Node").isInstance( varObject)) {
264                     newXObject = new XNodeSetForDOM ( new JSTLNodeList( (Node JavaDoc)varObject ),xctxt );
265                 } else if ( Class.forName("java.lang.String").isInstance( varObject)){
266                     newXObject = new XString ( (String JavaDoc)varObject );
267                 } else if ( Class.forName("java.lang.Boolean").isInstance( varObject) ) {
268                     newXObject = new XBoolean ( (Boolean JavaDoc)varObject );
269                 } else if ( Class.forName("java.lang.Number").isInstance( varObject) ) {
270                     newXObject = new XNumber ( (Number JavaDoc)varObject );
271                 }
272
273                 return newXObject;
274                // myvs.setGlobalVariable( i, newXObject );
275
} catch ( ClassNotFoundException JavaDoc cnfe ) {
276                 // This shouldn't happen (FIXME: LOG)
277
System.out.println("CLASS NOT FOUND EXCEPTION :" + cnfe );
278             }
279             //System.out.println("*****getVariableOrParam returning *null*" );
280
return null ;
281         }
282         
283         /**
284          * Retrieve an XPath's variable value using JSTL's custom
285          * variable-mapping rules
286          */

287         public Object JavaDoc getVariableValue(
288         String JavaDoc namespace,
289         String JavaDoc prefix,
290         String JavaDoc localName)
291         throws UnresolvableException
292         {
293             // p("resolving: ns=" + namespace + " prefix=" + prefix + " localName=" + localName);
294
// We can match on namespace with Xalan but leaving as is
295
// [ I 'd prefer to match on namespace, but this doesn't appear
296
// to work in Jaxen]
297
if (prefix == null || prefix.equals("")) {
298                 return notNull(
299                 pageContext.findAttribute(localName),
300                 prefix,
301                 localName);
302             } else if (prefix.equals(PAGE_P)) {
303                 return notNull(
304                 pageContext.getAttribute(localName,PageContext.PAGE_SCOPE),
305                 prefix,
306                 localName);
307             } else if (prefix.equals(REQUEST_P)) {
308                 return notNull(
309                 pageContext.getAttribute(localName,
310                 PageContext.REQUEST_SCOPE),
311                 prefix,
312                 localName);
313             } else if (prefix.equals(SESSION_P)) {
314                 return notNull(
315                 pageContext.getAttribute(localName,
316                 PageContext.SESSION_SCOPE),
317                 prefix,
318                 localName);
319             } else if (prefix.equals(APP_P)) {
320                 return notNull(
321                 pageContext.getAttribute(localName,
322                 PageContext.APPLICATION_SCOPE),
323                 prefix,
324                 localName);
325             } else if (prefix.equals(PARAM_P)) {
326                 return notNull(
327                 pageContext.getRequest().getParameter(localName),
328                 prefix,
329                 localName);
330             } else if (prefix.equals(INITPARAM_P)) {
331                 return notNull(
332                 pageContext.getServletContext().
333                 getInitParameter(localName),
334                 prefix,
335                 localName);
336             } else if (prefix.equals(HEADER_P)) {
337                 HttpServletRequest JavaDoc hsr =
338                 (HttpServletRequest JavaDoc) pageContext.getRequest();
339                 return notNull(
340                 hsr.getHeader(localName),
341                 prefix,
342                 localName);
343             } else if (prefix.equals(COOKIE_P)) {
344                 HttpServletRequest JavaDoc hsr =
345                 (HttpServletRequest JavaDoc) pageContext.getRequest();
346                 Cookie JavaDoc[] c = hsr.getCookies();
347                 for (int i = 0; i < c.length; i++)
348                     if (c[i].getName().equals(localName))
349                         return c[i].getValue();
350                 throw new UnresolvableException("$" + prefix + ":" + localName);
351             } else {
352                 throw new UnresolvableException("$" + prefix + ":" + localName);
353             }
354         }
355         
356         /**
357          * Validate that the Object returned is not null. If it is
358          * null, throw an exception.
359          */

360         private Object JavaDoc notNull(Object JavaDoc o, String JavaDoc prefix, String JavaDoc localName)
361         throws UnresolvableException {
362             if (o == null) {
363                 throw new UnresolvableException("$" + (prefix==null?"":prefix+":") + localName);
364             }
365             //p("resolved to: " + o);
366
return o;
367         }
368     }
369     
370     //*********************************************************************
371
// Support for XPath evaluation
372

373     private PageContext JavaDoc pageContext;
374     private static HashMap JavaDoc exprCache;
375     private static JSTLPrefixResolver jstlPrefixResolver = null;
376     
377     /** Initialize globally useful data. */
378     private synchronized static void staticInit() {
379         if (jstlPrefixResolver == null) {
380             // register supported namespaces
381
jstlPrefixResolver = new JSTLPrefixResolver();
382             jstlPrefixResolver.addNamespace("pageScope", PAGE_NS_URL);
383             jstlPrefixResolver.addNamespace("requestScope", REQUEST_NS_URL);
384             jstlPrefixResolver.addNamespace("sessionScope", SESSION_NS_URL);
385             jstlPrefixResolver.addNamespace("applicationScope", APP_NS_URL);
386             jstlPrefixResolver.addNamespace("param", PARAM_NS_URL);
387             jstlPrefixResolver.addNamespace("initParam", INITPARAM_NS_URL);
388             jstlPrefixResolver.addNamespace("header", HEADER_NS_URL);
389             jstlPrefixResolver.addNamespace("cookie", COOKIE_NS_URL);
390             
391             
392             // create a HashMap to cache the expressions
393
exprCache = new HashMap JavaDoc();
394         }
395     }
396     
397     static DocumentBuilderFactory JavaDoc dbf = null;
398     static DocumentBuilder JavaDoc db = null;
399     static Document JavaDoc d = null;
400     
401     static Document JavaDoc getDummyDocument( ) {
402         try {
403             if ( dbf == null ) {
404                 dbf = DocumentBuilderFactory.newInstance();
405                 dbf.setNamespaceAware( true );
406                 dbf.setValidating( false );
407             }
408             db = dbf.newDocumentBuilder();
409
410             DOMImplementation JavaDoc dim = db.getDOMImplementation();
411             d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null);
412             //d = db.newDocument();
413
return d;
414         } catch ( Exception JavaDoc e ) {
415             e.printStackTrace();
416         }
417         return null;
418     }
419
420      static Document JavaDoc getDummyDocumentWithoutRoot( ) {
421         try {
422             if ( dbf == null ) {
423                 dbf = DocumentBuilderFactory.newInstance();
424                 dbf.setNamespaceAware( true );
425                 dbf.setValidating( false );
426             }
427             db = dbf.newDocumentBuilder();
428
429             d = db.newDocument();
430             return d;
431         } catch ( Exception JavaDoc e ) {
432             e.printStackTrace();
433         }
434         return null;
435     }
436
437     private static Document JavaDoc getDocumentForNode(Node JavaDoc node) {
438         Document JavaDoc doc = getDummyDocumentWithoutRoot();
439         Node JavaDoc importedNode = doc.importNode(node, true);
440         doc.appendChild(importedNode);
441         return doc;
442     }
443     
444     // The following variable is used for holding the modified xpath string
445
// when adapting parameter for Xalan XPath engine, where we need to have
446
// a Non null context node.
447
String JavaDoc modifiedXPath = null;
448     
449
450     
451     
452     
453     /**
454      * Evaluate an XPath expression to a String value.
455      */

456     public String JavaDoc valueOf(Node JavaDoc n, String JavaDoc xpath) throws JspTagException JavaDoc {
457         //p("******** valueOf(" + n + ", " + xpath + ")");
458
staticInit();
459         // @@@ but where do we set the Pag4eContext for the varaiblecontext?
460
JstlVariableContext vs = new JstlVariableContext();
461         XPathContext xpathSupport = new XPathContext();
462         xpathSupport.setVarStack( vs);
463         
464         Vector JavaDoc varVector = fillVarStack(vs, xpathSupport);
465         
466         Node JavaDoc contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
467         
468         xpath = modifiedXPath;
469         
470         //p("******** valueOf: modified xpath: " + xpath);
471

472         XObject result = JSTLXPathAPI.eval( contextNode, xpath,
473         jstlPrefixResolver,xpathSupport, varVector);
474
475         
476         //p("******Result TYPE => " + result.getTypeString() );
477

478         String JavaDoc resultString = result.str();
479         //p("******** valueOf: after eval: " + resultString);
480

481         return resultString;
482     
483     }
484
485     /**
486      * Evaluate an XPath expression to a boolean value.
487      */

488     public boolean booleanValueOf(Node JavaDoc n, String JavaDoc xpath)
489     throws JspTagException JavaDoc {
490         
491         staticInit();
492         JstlVariableContext vs = new JstlVariableContext();
493         XPathContext xpathSupport = new XPathContext();
494         xpathSupport.setVarStack( vs);
495         
496         Vector JavaDoc varVector = fillVarStack(vs, xpathSupport);
497         
498         Node JavaDoc contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
499         xpath = modifiedXPath;
500         
501         XObject result = JSTLXPathAPI.eval( contextNode, xpath,
502         jstlPrefixResolver, xpathSupport, varVector);
503         
504         try {
505             return result.bool();
506         } catch (TransformerException JavaDoc ex) {
507             throw new JspTagException JavaDoc(
508                 Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);
509         }
510     }
511     
512     /**
513      * Evaluate an XPath expression to a List of nodes.
514      */

515     public List JavaDoc selectNodes(Node JavaDoc n, String JavaDoc xpath) throws JspTagException JavaDoc {
516         
517         staticInit();
518         JstlVariableContext vs = new JstlVariableContext();
519         XPathContext xpathSupport = new XPathContext();
520         xpathSupport.setVarStack( vs);
521         
522         Vector JavaDoc varVector = fillVarStack(vs, xpathSupport);
523
524         Node JavaDoc contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
525         xpath = modifiedXPath;
526         
527         XObject result = JSTLXPathAPI.eval( contextNode, xpath,
528         jstlPrefixResolver,xpathSupport, varVector);
529         try {
530             NodeList JavaDoc nl= JSTLXPathAPI.getNodeList(result);
531             return new JSTLNodeList( nl );
532         } catch ( JspTagException JavaDoc e ) {
533             try {
534                 //If result can't be converted to NodeList we receive exception
535
// In this case we may have single primitive value as the result
536
// Populating List with this value ( String, Boolean or Number )
537

538                 //System.out.println("JSTLXPathAPI.getNodeList thrown exception:"+ e);
539
Vector JavaDoc vector = new Vector JavaDoc();
540                 Object JavaDoc resultObject = null;
541                 if ( result.getType()== XObject.CLASS_BOOLEAN ) {
542                     resultObject = new Boolean JavaDoc( result.bool());
543                 } else if ( result.getType()== XObject.CLASS_NUMBER ) {
544                     resultObject = new Double JavaDoc( result.num());
545                 } else if ( result.getType()== XObject.CLASS_STRING ) {
546                     resultObject = result.str();
547                 }
548
549                 vector.add( resultObject );
550                 return new JSTLNodeList ( vector );
551             } catch ( TransformerException JavaDoc te ) {
552                 throw new JspTagException JavaDoc(te.toString(), te);
553             }
554         }
555           
556         
557        
558     }
559     
560     /**
561      * Evaluate an XPath expression to a single node.
562      */

563     public Node JavaDoc selectSingleNode(Node JavaDoc n, String JavaDoc xpath)
564     throws JspTagException JavaDoc {
565         //p("selectSingleNode of XPathUtil = passed node:" +
566
// "xpath => " + n + " : " + xpath );
567

568         staticInit();
569         JstlVariableContext vs = new JstlVariableContext();
570         XPathContext xpathSupport = new XPathContext();
571         xpathSupport.setVarStack( vs);
572         
573         Vector JavaDoc varVector = fillVarStack(vs, xpathSupport);
574
575         Node JavaDoc contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
576         xpath = modifiedXPath;
577         
578         return (Node JavaDoc) JSTLXPathAPI.selectSingleNode( contextNode, xpath,
579         jstlPrefixResolver,xpathSupport );
580     }
581     
582     /** Returns a locally appropriate context given a node. */
583     private VariableStack getLocalContext() {
584         // set up instance-specific contexts
585
VariableStack vc = new JstlVariableContext();
586         return vc;
587     }
588     
589     //*********************************************************************
590
// Adapt XPath expression for integration with Xalan
591

592     /**
593      * To evaluate an XPath expression using Xalan, we need
594      * to create an XPath object, which wraps an expression object and provides
595      * general services for execution of that expression.
596      *
597      * An XPath object can be instantiated with the following information:
598      * - XPath expression to evaluate
599      * - SourceLocator
600      * (reports where an error occurred in the XML source or
601      * transformation instructions)
602      * - PrefixResolver
603      * (resolve prefixes to namespace URIs)
604      * - type
605      * (one of SELECT or MATCH)
606      * - ErrorListener
607      * (customized error handling)
608      *
609      * Execution of the XPath expression represented by an XPath object
610      * is done via method execute which takes the following parameters:
611      * - XPathContext
612      * The execution context
613      * - Node contextNode
614      * The node that "." expresses
615      * - PrefixResolver namespaceContext
616      * The context in which namespaces in the XPath are supposed to be
617      * expanded.
618      *
619      * Given all of this, if no context node is set for the evaluation
620      * of the XPath expression, one must be set so Xalan
621      * can successfully evaluate a JSTL XPath expression.
622      * (it will not work if the context node is given as a varialbe
623      * at the beginning of the expression)
624      *
625      * @@@ Provide more details...
626      */

627     protected Node JavaDoc adaptParamsForXalan( JstlVariableContext jvc, Node JavaDoc n,
628     String JavaDoc xpath ) {
629         Node JavaDoc boundDocument = null;
630         
631         modifiedXPath = xpath;
632         String JavaDoc origXPath = xpath ;
633         boolean whetherOrigXPath = true;
634         
635         // If contextNode is not null then just pass the values to Xalan XPath
636
if ( n != null ) {
637             return n;
638         }
639         
640         if ( xpath.startsWith("$") ) {
641             // JSTL uses $scopePrefix:varLocalName/xpath expression
642

643             String JavaDoc varQName= xpath.substring( xpath.indexOf("$")+1);
644             if ( varQName.indexOf("/") > 0 ) {
645                 varQName = varQName.substring( 0, varQName.indexOf("/"));
646             }
647             String JavaDoc varPrefix = null;
648             String JavaDoc varLocalName = varQName;
649             if ( varQName.indexOf( ":") >= 0 ) {
650                 varPrefix = varQName.substring( 0, varQName.indexOf(":") );
651                 varLocalName = varQName.substring( varQName.indexOf(":")+1 );
652             }
653             
654             if ( xpath.indexOf("/") > 0 ) {
655                 xpath = xpath.substring( xpath.indexOf("/"));
656             } else {
657                 xpath = "/*";
658                 whetherOrigXPath = false;
659             }
660            
661             
662             try {
663                 Object JavaDoc varObject=jvc.getVariableValue( null,varPrefix,
664                 varLocalName);
665                 //System.out.println( "varObject => : its Class " +varObject +
666
// ":" + varObject.getClass() );
667

668                 if ( Class.forName("org.w3c.dom.Document").isInstance(
669                 varObject ) ) {
670                     //boundDocument = ((Document)varObject).getDocumentElement();
671
boundDocument = ((Document JavaDoc)varObject);
672                 } else {
673                     
674                     //System.out.println("Creating a Dummy document to pass " +
675
// " onto as context node " );
676

677                     if ( Class.forName("org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance( varObject ) ) {
678                         Document JavaDoc newDocument = getDummyDocument();
679
680                         JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
681                         if ( jstlNodeList.getLength() == 1 ) {
682                             if ( Class.forName("org.w3c.dom.Node").isInstance(
683                                 jstlNodeList.elementAt(0) ) ) {
684                                 Node JavaDoc node = (Node JavaDoc)jstlNodeList.elementAt(0);
685                                 boundDocument = getDocumentForNode(node);
686                                 if ( whetherOrigXPath ) {
687                                     xpath="/*" + xpath;
688                                 }
689
690                             } else {
691
692                                 //Nodelist with primitive type
693
Object JavaDoc myObject = jstlNodeList.elementAt(0);
694
695                                 //p("Single Element of primitive type");
696
//p("Type => " + myObject.getClass());
697

698                                 xpath = myObject.toString();
699
700                                 //p("String value ( xpathwould be this) => " + xpath);
701
boundDocument = newDocument;
702                             }
703                             
704                         } else {
705
706                             Element JavaDoc dummyroot = newDocument.getDocumentElement();
707                             for ( int i=0; i< jstlNodeList.getLength(); i++ ) {
708                                 Node JavaDoc currNode = (Node JavaDoc)jstlNodeList.item(i);
709                             
710                                 Node JavaDoc importedNode = newDocument.importNode(
711                                     currNode, true );
712
713                                 //printDetails ( newDocument);
714

715                                 dummyroot.appendChild( importedNode );
716
717                                 //p( "Details of the document After importing");
718
//printDetails ( newDocument);
719
}
720                             boundDocument = newDocument;
721                             // printDetails ( boundDocument );
722
//Verify :As we are adding Document element we need
723
// to change the xpath expression.Hopefully this
724
// won't change the result
725

726                             xpath = "/*" + xpath;
727                         }
728                     } else if ( Class.forName("org.w3c.dom.Node").isInstance(
729                     varObject ) ) {
730                         boundDocument = getDocumentForNode((Node JavaDoc)varObject);
731                         if (whetherOrigXPath) {
732                             xpath = "/*" + xpath;
733                         }
734                     } else {
735                         boundDocument = getDummyDocument();
736                         xpath = origXPath;
737                     }
738                     
739                     
740                 }
741             } catch ( UnresolvableException ue ) {
742                 // FIXME: LOG
743
System.out.println("Variable Unresolvable :" + ue.getMessage());
744                 ue.printStackTrace();
745             } catch ( ClassNotFoundException JavaDoc cnf ) {
746                 // Will never happen
747
}
748         } else {
749             //System.out.println("Not encountered $ Creating a Dummydocument 2 "+
750
// "pass onto as context node " );
751
boundDocument = getDummyDocument();
752         }
753      
754         modifiedXPath = xpath;
755         //System.out.println("Modified XPath::boundDocument =>" + modifiedXPath +
756
// "::" + boundDocument );
757

758         return boundDocument;
759     }
760     
761
762     //*********************************************************************
763
//
764

765     /**
766      ** @@@ why do we have to pass varVector in the varStack first, and then
767      * to XPath object?
768      */

769     private Vector JavaDoc fillVarStack(JstlVariableContext vs, XPathContext xpathSupport)
770     throws JspTagException JavaDoc {
771         org.apache.xpath.VariableStack myvs = xpathSupport.getVarStack();
772         Vector JavaDoc varVector = getVariableQNames();
773         for ( int i=0; i<varVector.size(); i++ ) {
774           
775             QName varQName = (QName)varVector.elementAt(i);
776
777             try {
778                 XObject variableValue = vs.getVariableOrParam( xpathSupport, varQName );
779                 //p("&&&&Variable set to => " + variableValue.toString() );
780
//p("&&&&Variable type => " + variableValue.getTypeString() );
781
myvs.setGlobalVariable( i, variableValue );
782
783             } catch ( TransformerException JavaDoc te ) {
784                 throw new JspTagException JavaDoc(te.toString(), te);
785             }
786  
787         }
788         return varVector;
789     }
790         
791     
792     
793     
794     
795     //*********************************************************************
796
// Static support for context retrieval from parent <forEach> tag
797

798     public static Node JavaDoc getContext(Tag JavaDoc t) throws JspTagException JavaDoc {
799         ForEachTag xt =
800         (ForEachTag) TagSupport.findAncestorWithClass(
801         t, ForEachTag.class);
802         if (xt == null)
803             return null;
804         else
805             return (xt.getContext());
806     }
807     
808     //*********************************************************************
809
// Utility methods
810

811     private static void p(String JavaDoc s) {
812         System.out.println("[XPathUtil] " + s);
813     }
814     
815     public static void printDetails(Node JavaDoc n) {
816         System.out.println("\n\nDetails of Node = > " + n ) ;
817         System.out.println("Name:Type:Node Value = > " + n.getNodeName() +
818         ":" + n.getNodeType() + ":" + n.getNodeValue() ) ;
819         System.out.println("Namespace URI : Prefix : localName = > " +
820         n.getNamespaceURI() + ":" +n.getPrefix() + ":" + n.getLocalName());
821         System.out.println("\n Node has children => " + n.hasChildNodes() );
822         if ( n.hasChildNodes() ) {
823             NodeList JavaDoc nl = n.getChildNodes();
824             System.out.println("Number of Children => " + nl.getLength() );
825             for ( int i=0; i<nl.getLength(); i++ ) {
826                 Node JavaDoc childNode = nl.item(i);
827                 printDetails( childNode );
828             }
829         }
830     }
831 }
832
833 class JSTLNodeList extends Vector JavaDoc implements NodeList JavaDoc {
834     
835     Vector JavaDoc nodeVector;
836
837     public JSTLNodeList ( Vector JavaDoc nodeVector ) {
838         this.nodeVector = nodeVector;
839     }
840
841     public JSTLNodeList ( NodeList JavaDoc nl ) {
842         nodeVector = new Vector JavaDoc();
843         //System.out.println("[JSTLNodeList] nodelist details");
844
for ( int i=0; i<nl.getLength(); i++ ) {
845             Node JavaDoc currNode = nl.item(i);
846             //XPathUtil.printDetails ( currNode );
847
nodeVector.add(i, nl.item(i) );
848         }
849     }
850
851     public JSTLNodeList ( Node JavaDoc n ) {
852         nodeVector = new Vector JavaDoc();
853         nodeVector.addElement( n );
854     }
855         
856
857     public Node JavaDoc item ( int index ) {
858         return (Node JavaDoc)nodeVector.elementAt( index );
859     }
860
861     public Object JavaDoc elementAt ( int index ) {
862         return nodeVector.elementAt( index );
863     }
864
865     public Object JavaDoc get ( int index ) {
866         return nodeVector.get( index );
867     }
868
869     public int getLength ( ) {
870         return nodeVector.size( );
871     }
872
873     public int size ( ) {
874         //System.out.println("JSTL node list size => " + nodeVector.size() );
875
return nodeVector.size( );
876     }
877
878     // Can implement other Vector methods to redirect those methods to
879
// the vector in the variable param. As we are not using them as part
880
// of this implementation we are not doing that here. If this changes
881
// then we need to override those methods accordingly
882

883 }
884          
885
886
887
888
Popular Tags