/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.taglibs.standard.tag.common.xml;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerException;
import org.apache.taglibs.standard.resources.Resources;
import org.apache.xml.utils.QName;
import org.apache.xpath.VariableStack;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XBoolean;
import org.apache.xpath.objects.XNodeSetForDOM;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XString;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* <p>Support for tag handlers that evaluate XPath expressions.</p>
*
* @author Shawn Bayern
* @author Ramesh Mandava ( ramesh.mandava@sun.com )
* @author Pierre Delisle ( pierre.delisle@sun.com )
*/
// would ideally be a base class, but some of our user handlers already
// have their own parents
public class XPathUtil {
//*********************************************************************
// Constructor
/**
* Constructs a new XPathUtil object associated with the given
* PageContext.
*/
public XPathUtil(PageContext pc) {
pageContext = pc;
}
int globalVarSize=0;
public Vector getVariableQNames ( ) {
globalVarSize = 0;
Vector variableVector = new Vector ( );
// Now construct attributes in different scopes
Enumeration enum_ = pageContext.getAttributeNamesInScope(
PageContext.PAGE_SCOPE );
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( PAGE_NS_URL, PAGE_P, varName);
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
variableVector.addElement( new QName(null, varName ) );
globalVarSize++;
}
enum_ = pageContext.getAttributeNamesInScope(
PageContext.REQUEST_SCOPE );
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( REQUEST_NS_URL,REQUEST_P, varName);
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
variableVector.addElement( new QName(null, varName ) );
globalVarSize++;
}
enum_ = pageContext.getAttributeNamesInScope(
PageContext.SESSION_SCOPE );
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( SESSION_NS_URL, SESSION_P,varName);
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
variableVector.addElement( new QName(null, varName ) );
globalVarSize++;
}
enum_ = pageContext.getAttributeNamesInScope(
PageContext.APPLICATION_SCOPE );
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( APP_NS_URL, APP_P,varName );
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
variableVector.addElement( new QName(null, varName ) );
globalVarSize++;
}
enum_ = pageContext.getRequest().getParameterNames();
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( PARAM_NS_URL, PARAM_P,varName );
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
}
enum_ = pageContext.getServletContext().getInitParameterNames();
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( INITPARAM_NS_URL, INITPARAM_P,varName );
//Adding both namespace qualified QName and just localName
variableVector.addElement( varQName );
globalVarSize++;
}
enum_ = ((HttpServletRequest)pageContext.getRequest()).getHeaderNames();
while ( enum_.hasMoreElements() ) {
String varName = (String)enum_.nextElement();
QName varQName = new QName ( HEADER_NS_URL, HEADER_P,varName );
//Adding namespace qualified QName
variableVector.addElement( varQName );
globalVarSize++;
}
Cookie[] c= ((HttpServletRequest)pageContext.getRequest()).getCookies();
if ( c!= null ) {
for (int i = 0; i < c.length; i++) {
String varName = c[i].getName();
QName varQName = new QName ( COOKIE_NS_URL, COOKIE_P,varName );
//Adding namespace qualified QName
variableVector.addElement( varQName );
globalVarSize++;
}
}
return variableVector;
}
//*********************************************************************
// Support for JSTL variable resolution
// The URLs
private static final String PAGE_NS_URL
= "http://java.sun.com/jstl/xpath/page";
private static final String REQUEST_NS_URL
= "http://java.sun.com/jstl/xpath/request";
private static final String SESSION_NS_URL
= "http://java.sun.com/jstl/xpath/session";
private static final String APP_NS_URL
= "http://java.sun.com/jstl/xpath/app";
private static final String PARAM_NS_URL
= "http://java.sun.com/jstl/xpath/param";
private static final String INITPARAM_NS_URL
= "http://java.sun.com/jstl/xpath/initParam";
private static final String COOKIE_NS_URL
= "http://java.sun.com/jstl/xpath/cookie";
private static final String HEADER_NS_URL
= "http://java.sun.com/jstl/xpath/header";
// The prefixes
private static final String PAGE_P = "pageScope";
private static final String REQUEST_P = "requestScope";
private static final String SESSION_P = "sessionScope";
private static final String APP_P = "applicationScope";
private static final String PARAM_P = "param";
private static final String INITPARAM_P = "initParam";
private static final String COOKIE_P = "cookie";
private static final String HEADER_P = "header";
/**
* org.apache.xpath.VariableStack defines a class to keep track of a stack
* for template arguments and variables.
* JstlVariableContext customizes it so it handles JSTL custom
* variable-mapping rules.
*/
protected class JstlVariableContext extends org.apache.xpath.VariableStack {
public JstlVariableContext( ) {
super();
}
/**
* Get a variable as an XPath object based on it's qualified name.
* We override the base class method so JSTL's custom variable-mapping
* rules can be applied.
*
* @param xctxt The XPath context. @@@ we don't use it...
* (from xalan: which must be passed in order to lazy evaluate variables.)
* @param qname The qualified name of the variable.
*/
public XObject getVariableOrParam(
XPathContext xctxt,
org.apache.xml.utils.QName qname)
throws javax.xml.transform.TransformerException, UnresolvableException
{
//p( "***********************************getVariableOrParam begin****");
String namespace = qname.getNamespaceURI();
String prefix = qname.getPrefix();
String localName = qname.getLocalName();
//p("namespace:prefix:localname=>"+ namespace
// + ":" + prefix +":" + localName );
try {
Object varObject = getVariableValue(namespace,prefix,localName);
//XObject varObject = myvs.getVariableOrParam( xpathSupport, varQName);
XObject newXObject = new XObject( varObject);
if ( Class.forName("org.w3c.dom.Document").isInstance( varObject) ) {
NodeList nl= ((Document)varObject).getChildNodes();
// To allow non-welformed document
Vector nodeVector = new Vector();
for ( int i=0; i<nl.getLength(); i++ ) {
Node currNode = nl.item(i);
if ( currNode.getNodeType() == Node.ELEMENT_NODE ) {
nodeVector.addElement( currNode);
}
}
JSTLNodeList jstlNodeList = new JSTLNodeList( nodeVector);
newXObject = new XNodeSetForDOM( jstlNodeList, xctxt );
return newXObject;
}
if ( Class.forName(
"org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(
varObject) ) {
JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
if ( ( jstlNodeList.getLength() == 1 ) &&
(!Class.forName("org.w3c.dom.Node").isInstance( jstlNodeList.elementAt(0) ) ) ) {
varObject = jstlNodeList.elementAt(0);
//Now we need to allow this primitive type to be coverted
// to type which Xalan XPath understands
} else {
return new XNodeSetForDOM ( jstlNodeList ,xctxt );
}
}
if (Class.forName("org.w3c.dom.Node").isInstance( varObject)) {
newXObject = new XNodeSetForDOM ( new JSTLNodeList( (Node)varObject ),xctxt );
} else if ( Class.forName("java.lang.String").isInstance( varObject)){
newXObject = new XString ( (String)varObject );
} else if ( Class.forName("java.lang.Boolean").isInstance( varObject) ) {
newXObject = new XBoolean ( (Boolean)varObject );
} else if ( Class.forName("java.lang.Number").isInstance( varObject) ) {
newXObject = new XNumber ( (Number)varObject );
}
return newXObject;
// myvs.setGlobalVariable( i, newXObject );
} catch ( ClassNotFoundException cnfe ) {
// This shouldn't happen (FIXME: LOG)
System.out.println("CLASS NOT FOUND EXCEPTION :" + cnfe );
}
//System.out.println("*****getVariableOrParam returning *null*" );
return null ;
}
/**
* Retrieve an XPath's variable value using JSTL's custom
* variable-mapping rules
*/
public Object getVariableValue(
String namespace,
String prefix,
String localName)
throws UnresolvableException
{
// p("resolving: ns=" + namespace + " prefix=" + prefix + " localName=" + localName);
// We can match on namespace with Xalan but leaving as is
// [ I 'd prefer to match on namespace, but this doesn't appear
// to work in Jaxen]
if (prefix == null || prefix.equals("")) {
return notNull(
pageContext.findAttribute(localName),
prefix,
localName);
} else if (prefix.equals(PAGE_P)) {
return notNull(
pageContext.getAttribute(localName,PageContext.PAGE_SCOPE),
prefix,
localName);
} else if (prefix.equals(REQUEST_P)) {
return notNull(
pageContext.getAttribute(localName,
PageContext.REQUEST_SCOPE),
prefix,
localName);
} else if (prefix.equals(SESSION_P)) {
return notNull(
pageContext.getAttribute(localName,
PageContext.SESSION_SCOPE),
prefix,
localName);
} else if (prefix.equals(APP_P)) {
return notNull(
pageContext.getAttribute(localName,
PageContext.APPLICATION_SCOPE),
prefix,
localName);
} else if (prefix.equals(PARAM_P)) {
return notNull(
pageContext.getRequest().getParameter(localName),
prefix,
localName);
} else if (prefix.equals(INITPARAM_P)) {
return notNull(
pageContext.getServletContext().
getInitParameter(localName),
prefix,
localName);
} else if (prefix.equals(HEADER_P)) {
HttpServletRequest hsr =
(HttpServletRequest) pageContext.getRequest();
return notNull(
hsr.getHeader(localName),
prefix,
localName);
} else if (prefix.equals(COOKIE_P)) {
HttpServletRequest hsr =
(HttpServletRequest) pageContext.getRequest();
Cookie[] c = hsr.getCookies();
for (int i = 0; i < c.length; i++)
if (c[i].getName().equals(localName))
return c[i].getValue();
throw new UnresolvableException("$" + prefix + ":" + localName);
} else {
throw new UnresolvableException("$" + prefix + ":" + localName);
}
}
/**
* Validate that the Object returned is not null. If it is
* null, throw an exception.
*/
private Object notNull(Object o, String prefix, String localName)
throws UnresolvableException {
if (o == null) {
throw new UnresolvableException("$" + (prefix==null?"":prefix+":") + localName);
}
//p("resolved to: " + o);
return o;
}
}
//*********************************************************************
// Support for XPath evaluation
private PageContext pageContext;
private static HashMap exprCache;
private static JSTLPrefixResolver jstlPrefixResolver = null;
/** Initialize globally useful data. */
private synchronized static void staticInit() {
if (jstlPrefixResolver == null) {
// register supported namespaces
jstlPrefixResolver = new JSTLPrefixResolver();
jstlPrefixResolver.addNamespace("pageScope", PAGE_NS_URL);
jstlPrefixResolver.addNamespace("requestScope", REQUEST_NS_URL);
jstlPrefixResolver.addNamespace("sessionScope", SESSION_NS_URL);
jstlPrefixResolver.addNamespace("applicationScope", APP_NS_URL);
jstlPrefixResolver.addNamespace("param", PARAM_NS_URL);
jstlPrefixResolver.addNamespace("initParam", INITPARAM_NS_URL);
jstlPrefixResolver.addNamespace("header", HEADER_NS_URL);
jstlPrefixResolver.addNamespace("cookie", COOKIE_NS_URL);
// create a HashMap to cache the expressions
exprCache = new HashMap();
}
}
static DocumentBuilderFactory dbf = null;
static DocumentBuilder db = null;
static Document d = null;
static Document getDummyDocument( ) {
try {
if ( dbf == null ) {
dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware( true );
dbf.setValidating( false );
}
db = dbf.newDocumentBuilder();
DOMImplementation dim = db.getDOMImplementation();
d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null);
//d = db.newDocument();
return d;
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
}
static Document getDummyDocumentWithoutRoot( ) {
try {
if ( dbf == null ) {
dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware( true );
dbf.setValidating( false );
}
db = dbf.newDocumentBuilder();
d = db.newDocument();
return d;
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
}
private static Document getDocumentForNode(Node node) {
Document doc = getDummyDocumentWithoutRoot();
Node importedNode = doc.importNode(node, true);
doc.appendChild(importedNode);
return doc;
}
// The following variable is used for holding the modified xpath string
// when adapting parameter for Xalan XPath engine, where we need to have
// a Non null context node.
String modifiedXPath = null;
/**
* Evaluate an XPath expression to a String value.
*/
public String valueOf(Node n, String xpath) throws JspTagException {
//p("******** valueOf(" + n + ", " + xpath + ")");
staticInit();
// @@@ but where do we set the Pag4eContext for the varaiblecontext?
JstlVariableContext vs = new JstlVariableContext();
XPathContext xpathSupport = new XPathContext();
xpathSupport.setVarStack( vs);
Vector varVector = fillVarStack(vs, xpathSupport);
Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
xpath = modifiedXPath;
//p("******** valueOf: modified xpath: " + xpath);
XObject result = JSTLXPathAPI.eval( contextNode, xpath,
jstlPrefixResolver,xpathSupport, varVector);
//p("******Result TYPE => " + result.getTypeString() );
String resultString = result.str();
//p("******** valueOf: after eval: " + resultString);
return resultString;
}
/**
* Evaluate an XPath expression to a boolean value.
*/
public boolean booleanValueOf(Node n, String xpath)
throws JspTagException {
staticInit();
JstlVariableContext vs = new JstlVariableContext();
XPathContext xpathSupport = new XPathContext();
xpathSupport.setVarStack( vs);
Vector varVector = fillVarStack(vs, xpathSupport);
Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
xpath = modifiedXPath;
XObject result = JSTLXPathAPI.eval( contextNode, xpath,
jstlPrefixResolver, xpathSupport, varVector);
try {
return result.bool();
} catch (TransformerException ex) {
throw new JspTagException(
Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);
}
}
/**
* Evaluate an XPath expression to a List of nodes.
*/
public List selectNodes(Node n, String xpath) throws JspTagException {
staticInit();
JstlVariableContext vs = new JstlVariableContext();
XPathContext xpathSupport = new XPathContext();
xpathSupport.setVarStack( vs);
Vector varVector = fillVarStack(vs, xpathSupport);
Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
xpath = modifiedXPath;
XObject result = JSTLXPathAPI.eval( contextNode, xpath,
jstlPrefixResolver,xpathSupport, varVector);
try {
NodeList nl= JSTLXPathAPI.getNodeList(result);
return new JSTLNodeList( nl );
} catch ( JspTagException e ) {
try {
//If result can't be converted to NodeList we receive exception
// In this case we may have single primitive value as the result
// Populating List with this value ( String, Boolean or Number )
//System.out.println("JSTLXPathAPI.getNodeList thrown exception:"+ e);
Vector vector = new Vector();
Object resultObject = null;
if ( result.getType()== XObject.CLASS_BOOLEAN ) {
resultObject = new Boolean( result.bool());
} else if ( result.getType()== XObject.CLASS_NUMBER ) {
resultObject = new Double( result.num());
} else if ( result.getType()== XObject.CLASS_STRING ) {
resultObject = result.str();
}
vector.add( resultObject );
return new JSTLNodeList ( vector );
} catch ( TransformerException te ) {
throw new JspTagException(te.toString(), te);
}
}
}
/**
* Evaluate an XPath expression to a single node.
*/
public Node selectSingleNode(Node n, String xpath)
throws JspTagException {
//p("selectSingleNode of XPathUtil = passed node:" +
// "xpath => " + n + " : " + xpath );
staticInit();
JstlVariableContext vs = new JstlVariableContext();
XPathContext xpathSupport = new XPathContext();
xpathSupport.setVarStack( vs);
Vector varVector = fillVarStack(vs, xpathSupport);
Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
xpath = modifiedXPath;
return (Node) JSTLXPathAPI.selectSingleNode( contextNode, xpath,
jstlPrefixResolver,xpathSupport );
}
/** Returns a locally appropriate context given a node. */
private VariableStack getLocalContext() {
// set up instance-specific contexts
VariableStack vc = new JstlVariableContext();
return vc;
}
//*********************************************************************
// Adapt XPath expression for integration with Xalan
/**
* To evaluate an XPath expression using Xalan, we need
* to create an XPath object, which wraps an expression object and provides
* general services for execution of that expression.
*
* An XPath object can be instantiated with the following information:
* - XPath expression to evaluate
* - SourceLocator
* (reports where an error occurred in the XML source or
* transformation instructions)
* - PrefixResolver
* (resolve prefixes to namespace URIs)
* - type
* (one of SELECT or MATCH)
* - ErrorListener
* (customized error handling)
*
* Execution of the XPath expression represented by an XPath object
* is done via method execute which takes the following parameters:
* - XPathContext
* The execution context
* - Node contextNode
* The node that "." expresses
* - PrefixResolver namespaceContext
* The context in which namespaces in the XPath are supposed to be
* expanded.
*
* Given all of this, if no context node is set for the evaluation
* of the XPath expression, one must be set so Xalan
* can successfully evaluate a JSTL XPath expression.
* (it will not work if the context node is given as a varialbe
* at the beginning of the expression)
*
* @@@ Provide more details...
*/
protected Node adaptParamsForXalan( JstlVariableContext jvc, Node n,
String xpath ) {
Node boundDocument = null;
modifiedXPath = xpath;
String origXPath = xpath ;
boolean whetherOrigXPath = true;
// If contextNode is not null then just pass the values to Xalan XPath
if ( n != null ) {
return n;
}
if ( xpath.startsWith("$") ) {
// JSTL uses $scopePrefix:varLocalName/xpath expression
String varQName= xpath.substring( xpath.indexOf("$")+1);
if ( varQName.indexOf("/") > 0 ) {
varQName = varQName.substring( 0, varQName.indexOf("/"));
}
String varPrefix = null;
String varLocalName = varQName;
if ( varQName.indexOf( ":") >= 0 ) {
varPrefix = varQName.substring( 0, varQName.indexOf(":") );
varLocalName = varQName.substring( varQName.indexOf(":")+1 );
}
if ( xpath.indexOf("/") > 0 ) {
xpath = xpath.substring( xpath.indexOf("/"));
} else {
xpath = "/*";
whetherOrigXPath = false;
}
try {
Object varObject=jvc.getVariableValue( null,varPrefix,
varLocalName);
//System.out.println( "varObject => : its Class " +varObject +
// ":" + varObject.getClass() );
if ( Class.forName("org.w3c.dom.Document").isInstance(
varObject ) ) {
//boundDocument = ((Document)varObject).getDocumentElement();
boundDocument = ((Document)varObject);
} else {
//System.out.println("Creating a Dummy document to pass " +
// " onto as context node " );
if ( Class.forName("org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance( varObject ) ) {
Document newDocument = getDummyDocument();
JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
if ( jstlNodeList.getLength() == 1 ) {
if ( Class.forName("org.w3c.dom.Node").isInstance(
jstlNodeList.elementAt(0) ) ) {
Node node = (Node)jstlNodeList.elementAt(0);
boundDocument = getDocumentForNode(node);
if ( whetherOrigXPath ) {
xpath="/*" + xpath;
}
} else {
//Nodelist with primitive type
Object myObject = jstlNodeList.elementAt(0);
//p("Single Element of primitive type");
//p("Type => " + myObject.getClass());
xpath = myObject.toString();
//p("String value ( xpathwould be this) => " + xpath);
boundDocument = newDocument;
}
} else {
Element dummyroot = newDocument.getDocumentElement();
for ( int i=0; i< jstlNodeList.getLength(); i++ ) {
Node currNode = (Node)jstlNodeList.item(i);
Node importedNode = newDocument.importNode(
currNode, true );
//printDetails ( newDocument);
dummyroot.appendChild( importedNode );
//p( "Details of the document After importing");
//printDetails ( newDocument);
}
boundDocument = newDocument;
// printDetails ( boundDocument );
//Verify :As we are adding Document element we need
// to change the xpath expression.Hopefully this
// won't change the result
xpath = "/*" + xpath;
}
} else if ( Class.forName("org.w3c.dom.Node").isInstance(
varObject ) ) {
boundDocument = getDocumentForNode((Node)varObject);
if (whetherOrigXPath) {
xpath = "/*" + xpath;
}
} else {
boundDocument = getDummyDocument();
xpath = origXPath;
}
}
} catch ( UnresolvableException ue ) {
// FIXME: LOG
System.out.println("Variable Unresolvable :" + ue.getMessage());
ue.printStackTrace();
} catch ( ClassNotFoundException cnf ) {
// Will never happen
}
} else {
//System.out.println("Not encountered $ Creating a Dummydocument 2 "+
// "pass onto as context node " );
boundDocument = getDummyDocument();
}
modifiedXPath = xpath;
//System.out.println("Modified XPath::boundDocument =>" + modifiedXPath +
// "::" + boundDocument );
return boundDocument;
}
//*********************************************************************
//
/**
** @@@ why do we have to pass varVector in the varStack first, and then
* to XPath object?
*/
private Vector fillVarStack(JstlVariableContext vs, XPathContext xpathSupport)
throws JspTagException {
org.apache.xpath.VariableStack myvs = xpathSupport.getVarStack();
Vector varVector = getVariableQNames();
for ( int i=0; i<varVector.size(); i++ ) {
QName varQName = (QName)varVector.elementAt(i);
try {
XObject variableValue = vs.getVariableOrParam( xpathSupport, varQName );
//p("&&&&Variable set to => " + variableValue.toString() );
//p("&&&&Variable type => " + variableValue.getTypeString() );
myvs.setGlobalVariable( i, variableValue );
} catch ( TransformerException te ) {
throw new JspTagException(te.toString(), te);
}
}
return varVector;
}
//*********************************************************************
// Static support for context retrieval from parent <forEach> tag
public static Node getContext(Tag t) throws JspTagException {
ForEachTag xt =
(ForEachTag) TagSupport.findAncestorWithClass(
t, ForEachTag.class);
if (xt == null)
return null;
else
return (xt.getContext());
}
//*********************************************************************
// Utility methods
private static void p(String s) {
System.out.println("[XPathUtil] " + s);
}
public static void printDetails(Node n) {
System.out.println("\n\nDetails of Node = > " + n ) ;
System.out.println("Name:Type:Node Value = > " + n.getNodeName() +
":" + n.getNodeType() + ":" + n.getNodeValue() ) ;
System.out.println("Namespace URI : Prefix : localName = > " +
n.getNamespaceURI() + ":" +n.getPrefix() + ":" + n.getLocalName());
System.out.println("\n Node has children => " + n.hasChildNodes() );
if ( n.hasChildNodes() ) {
NodeList nl = n.getChildNodes();
System.out.println("Number of Children => " + nl.getLength() );
for ( int i=0; i<nl.getLength(); i++ ) {
Node childNode = nl.item(i);
printDetails( childNode );
}
}
}
}
class JSTLNodeList extends Vector implements NodeList {
Vector nodeVector;
public JSTLNodeList ( Vector nodeVector ) {
this.nodeVector = nodeVector;
}
public JSTLNodeList ( NodeList nl ) {
nodeVector = new Vector();
//System.out.println("[JSTLNodeList] nodelist details");
for ( int i=0; i<nl.getLength(); i++ ) {
Node currNode = nl.item(i);
//XPathUtil.printDetails ( currNode );
nodeVector.add(i, nl.item(i) );
}
}
public JSTLNodeList ( Node n ) {
nodeVector = new Vector();
nodeVector.addElement( n );
}
public Node item ( int index ) {
return (Node)nodeVector.elementAt( index );
}
public Object elementAt ( int index ) {
return nodeVector.elementAt( index );
}
public Object get ( int index ) {
return nodeVector.get( index );
}
public int getLength ( ) {
return nodeVector.size( );
}
public int size ( ) {
//System.out.println("JSTL node list size => " + nodeVector.size() );
return nodeVector.size( );
}
// Can implement other Vector methods to redirect those methods to
// the vector in the variable param. As we are not using them as part
// of this implementation we are not doing that here. If this changes
// then we need to override those methods accordingly
}