All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.taglibs.standard.tag.common.xml.XPathUtil Maven / Gradle / Ivy

The newest version!
/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License").  You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * glassfish/bootstrap/legal/CDDLv1.0.txt or
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable,
 * add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your
 * own identifying information: Portions Copyright [yyyy]
 * [name of copyright owner]
 *
 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
 *
 * Portions Copyright Apache Software Foundation.
 */

package org.apache.taglibs.standard.tag.common.xml;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.security.AccessController;
import java.security.PrivilegedAction;

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 javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathVariableResolver;
import javax.xml.xpath.XPathFactoryConfigurationException;

import org.apache.taglibs.standard.resources.Resources;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 

Support for tag handlers that evaluate XPath expressions.

* * @author Shawn Bayern * @author Ramesh Mandava ( [email protected] ) * @author Pierre Delisle ( [email protected] ) */ // 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; } //********************************************************************* // 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"; //********************************************************************* // Support for XPath evaluation private PageContext pageContext; private static HashMap exprCache; private static JSTLXPathNamespaceContext jstlXPathNamespaceContext = null; private static final String XPATH_FACTORY_CLASS_NAME = "org.apache.taglibs.standard.tag.common.xml.JSTLXPathFactory"; private static XPathFactory XPATH_FACTORY; static { // If the system property DEFAULT_PROPERTY_NAME + ":uri" is present, // where uri is the parameter to this method, then its value is read // as a class name. The method will try to create a new instance of // this class by using the class loader, and returns it if it is // successfully created. if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction(){ public Object run(){ System.setProperty(XPathFactory.DEFAULT_PROPERTY_NAME + ":" + XPathFactory.DEFAULT_OBJECT_MODEL_URI, XPATH_FACTORY_CLASS_NAME); return null; } }); } else { System.setProperty(XPathFactory.DEFAULT_PROPERTY_NAME + ":" + XPathFactory.DEFAULT_OBJECT_MODEL_URI, XPATH_FACTORY_CLASS_NAME); } try { XPATH_FACTORY = XPathFactory.newInstance(XPathFactory.DEFAULT_OBJECT_MODEL_URI); } catch (XPathFactoryConfigurationException xpce) { xpce.printStackTrace(); } } /** Initialize globally useful data. */ private synchronized static void staticInit() { if (jstlXPathNamespaceContext == null) { // register supported namespaces jstlXPathNamespaceContext = new JSTLXPathNamespaceContext(); jstlXPathNamespaceContext.addNamespace("pageScope", PAGE_NS_URL); jstlXPathNamespaceContext.addNamespace("requestScope", REQUEST_NS_URL); jstlXPathNamespaceContext.addNamespace("sessionScope", SESSION_NS_URL); jstlXPathNamespaceContext.addNamespace("applicationScope", APP_NS_URL); jstlXPathNamespaceContext.addNamespace("param", PARAM_NS_URL); jstlXPathNamespaceContext.addNamespace("initParam", INITPARAM_NS_URL); jstlXPathNamespaceContext.addNamespace("header", HEADER_NS_URL); jstlXPathNamespaceContext.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; } // 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 xpathString) throws JspTagException { // p("******** valueOf(" + n + ", " + xpathString + ")"); staticInit(); XPathVariableResolver jxvr = new JSTLXPathVariableResolver(pageContext); Node contextNode = adaptParamsForXalan(n, xpathString.trim(), jxvr); XPath xpath = XPATH_FACTORY.newXPath(); xpath.setNamespaceContext(jstlXPathNamespaceContext); xpath.setXPathVariableResolver(jxvr); try { return xpath.evaluate(xpathString, contextNode); } catch (XPathExpressionException ex) { throw new JspTagException(ex.toString(), ex); } } /** * Evaluate an XPath expression to a boolean value. */ public boolean booleanValueOf(Node n, String xpathString) throws JspTagException { staticInit(); XPathVariableResolver jxvr = new JSTLXPathVariableResolver(pageContext); Node contextNode = adaptParamsForXalan(n, xpathString.trim(), jxvr); xpathString = modifiedXPath; XPath xpath = XPATH_FACTORY.newXPath(); xpath.setNamespaceContext(jstlXPathNamespaceContext); xpath.setXPathVariableResolver(jxvr); try { return ((Boolean) xpath.evaluate( xpathString, contextNode, XPathConstants.BOOLEAN)).booleanValue(); } catch (XPathExpressionException 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 xpathString) throws JspTagException { staticInit(); XPathVariableResolver jxvr = new JSTLXPathVariableResolver(pageContext); Node contextNode = adaptParamsForXalan(n, xpathString.trim(), jxvr); xpathString = modifiedXPath; try { XPath xpath = XPATH_FACTORY.newXPath(); xpath.setNamespaceContext(jstlXPathNamespaceContext); xpath.setXPathVariableResolver(jxvr); Object nl = xpath.evaluate( xpathString, contextNode, JSTLXPathConstants.OBJECT); return new JSTLNodeList( nl ); } catch (XPathExpressionException ex ) { throw new JspTagException(ex.toString(), ex); } } /** * Evaluate an XPath expression to a single node. */ public Node selectSingleNode(Node n, String xpathString) throws JspTagException { //p("selectSingleNode of XPathUtil = passed node:" + // "xpathString => " + n + " : " + xpathString ); staticInit(); XPathVariableResolver jxvr = new JSTLXPathVariableResolver(pageContext); Node contextNode = adaptParamsForXalan(n, xpathString.trim(), jxvr); xpathString = modifiedXPath; try { XPath xpath = XPATH_FACTORY.newXPath(); xpath.setNamespaceContext(jstlXPathNamespaceContext); xpath.setXPathVariableResolver(jxvr); return (Node) xpath.evaluate( xpathString, contextNode, XPathConstants.NODE); } catch (XPathExpressionException ex) { throw new JspTagException(ex.toString(), ex); } } //********************************************************************* // 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(Node n, String xpath, XPathVariableResolver jxvr) { 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=((JSTLXPathVariableResolver) jxvr).getVariableValue("", varPrefix, varLocalName); //p( "varObject => : its Class " +varObject + // ":" + varObject.getClass() ); if ( Class.forName("org.w3c.dom.Document").isInstance( varObject ) ) { //boundDocument = ((Document)varObject).getDocumentElement(); boundDocument = ((Document)varObject); } else { //p("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); Document doc = getDummyDocumentWithoutRoot(); Node importedNode = doc.importNode( node, true); doc.appendChild (importedNode ); boundDocument = doc; 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 = (Node)varObject; } else { boundDocument = getDummyDocument(); xpath = origXPath; } } } catch ( UnresolvableException ue ) { // FIXME: LOG // p("Variable Unresolvable :" + ue.getMessage()); ue.printStackTrace(); } catch ( ClassNotFoundException cnf ) { // Will never happen } } else { //p("Not encountered $ Creating a Dummydocument 2 "+ // "pass onto as context node " ); boundDocument = getDummyDocument(); } modifiedXPath = xpath; //p("Modified XPath::boundDocument =>" + modifiedXPath + // "::" + boundDocument ); return boundDocument; } //********************************************************************* // //********************************************************************* // Static support for context retrieval from parent tag public static Node getContext(Tag t) throws JspTagException { ForEachTag xt = (ForEachTag) TagSupport.findAncestorWithClass( t, ForEachTag.class); if (xt == null) return null; else return (xt.getContext()); } //********************************************************************* // Utility methods private static void p(String s) { System.out.println("[XPathUtil] " + s); } public static void printDetails(Node n) { p("\n\nDetails of Node = > " + n ) ; p("Name:Type:Node Value = > " + n.getNodeName() + ":" + n.getNodeType() + ":" + n.getNodeValue() ) ; p("Namespace URI : Prefix : localName = > " + n.getNamespaceURI() + ":" +n.getPrefix() + ":" + n.getLocalName()); p("\n Node has children => " + n.hasChildNodes() ); if ( n.hasChildNodes() ) { NodeList nl = n.getChildNodes(); p("Number of Children => " + nl.getLength() ); for ( int i=0; i " + 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 }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy