blob: d6fbc2c779506a297b8c86c9d24d5417f1eba50f [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.xslt;
import org.apache.xpath.*;
import org.apache.xpath.compiler.XPathParser;
import org.apache.xpath.compiler.Compiler;
import org.apache.xalan.xpath.XObject;
import org.apache.xalan.xpath.XString;
import org.apache.xalan.xpath.XNodeSet;
import org.apache.xalan.xpath.XBoolean;
import org.apache.xalan.xpath.XNumber;
import org.apache.xalan.xpath.XNull;
import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.ContentHandler;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.xml.sax.ext.*;
import org.xml.sax.helpers.ParserAdapter;
import org.apache.xml.serialize.XMLSerializer;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.Templates;
import javax.xml.transform.Source;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.ErrorListener;
import java.util.*;
import java.net.*;
import java.io.*;
import java.lang.reflect.*;
import org.apache.xalan.templates.Stylesheet;
//import org.apache.xalan.templates.StylesheetRoot;
import org.apache.xalan.xpath.xml.XMLParserLiaison;
import org.apache.xalan.xpath.xml.ProblemListenerDefault;
import org.apache.xalan.xpath.xml.ProblemListener;
import org.apache.xalan.templates.StylesheetComposed;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.processor.StylesheetHandler;
import org.apache.xalan.processor.TransformerFactoryImpl;
//import org.apache.xalan.processor.ProcessorStylesheet;
//import org.apache.xalan.xslt.StylesheetSpec;
import org.apache.xalan.trace.*;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.res.XSLMessages;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xml.utils.TreeWalker;
import org.apache.xml.utils.QName;
import org.apache.xml.utils.DefaultErrorHandler;
import org.apache.xalan.transformer.TransformerHandlerImpl;
// Imported JAVA API for XML Parsing 1.0 classes
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
* <meta name="usage" content="advanced"/>
* The Xalan workhorse -- Collaborates with the XML parser liaison, the DOM,
* and the XPath engine, to transform a source tree of nodes into a result tree
* according to instructions and templates specified by a stylesheet tree.
* We suggest you use one of the
* static XSLTProcessorFactory getProcessor() methods to instantiate the processor
* and return an interface that greatly simplifies the process of manipulating
* XSLTEngineImpl.
*
* <p>The methods <code>process(...)</code> are the primary public entry points.
* The best way to perform transformations is to use the
* {@link org.apache.xalan.xslt.XSLTProcessor#process(org.apache.xalan.xslt.XSLTInputSource, org.apache.xalan.xslt.XSLTInputSource, org.apache.xalan.xslt.XSLTResultTarget)} method,
* but you may use any of process methods defined in XSLTEngineImpl.</p>
*
* <p>Please note that this class is not safe per instance over multiple
* threads. If you are in a multithreaded environment, you should
* keep a pool of these objects, or create a new one each time. In a
* multithreaded environment, the right way to do things is to create a
* StylesheetRoot via processStylesheet, and then reuse this object
* over multiple threads.</p>
*
* <p>If you reuse the processor instance, you should call reset() between transformations.</p>
* @see XSLTProcessorFactory
* @see XSLTProcessor
* @deprecated This compatibility layer will be removed in later releases.
*/
public class XSLTEngineImpl implements XSLTProcessor
{
//private Processor m_processor;
private TransformerFactory m_tfactory;
private TransformerImpl m_transformerImpl;
private DOM2Helper m_liaison;
private String m_outputFileName;
private DocumentHandler m_documentHandler = null;
private ProblemListenerDefault m_problemListener;
private Hashtable m_stylesheetParams;
StylesheetRoot m_stylesheetRoot = null;
Vector m_evalList = null;
boolean m_needToEval = false;
/*
* If this is true, then the diag function will
* be called.
*/
private boolean m_traceTemplateChildren = false;
/*
* If this is true, then the simple tracing of templates
* will be performed.
*/
private boolean m_traceTemplates = false;
/*
* If this is true, then diagnostics of each select
* will be performed.
*/
boolean m_traceSelects = false;
/*
* A stream to print diagnostics to.
*/
java.io.PrintWriter m_diagnosticsPrintWriter = null;
/* For diagnostics */
Hashtable m_durationsTable = new Hashtable();
/**
* A XSLMessages instance capable of producing user messages.
*/
private static XSLMessages m_XSLMessages = new XSLMessages();
/**
* Construct an XSLT processor that uses the default DTM (Document Table Model) liaison
* and XML parser. As a general rule, you should use XSLTProcessorFactory to create an
* instance of this class and provide access to the instance via the XSLTProcessor interface.
*
* @see XSLTProcessorFactory
* @see XSLTProcessor
*/
protected XSLTEngineImpl()
throws org.xml.sax.SAXException
{
m_tfactory = TransformerFactory.newInstance();
m_problemListener = new ProblemListenerDefault();
//m_liaison = (DOM2Helper)createLiaison();
}
/**
* Construct an XSLT processor that uses the the given parser liaison.
* As a general rule, you should use XSLTProcessorFactory to create an
* instance of this class and provide access to the instance via the XSLTProcessor interface.
*
* @see XSLTProcessorFactory
* @see XSLTProcessor
*/
public XSLTEngineImpl(String liaisonClassName)
throws SAXException
{
m_tfactory = TransformerFactory.newInstance();
m_problemListener = new ProblemListenerDefault();
try
{
m_liaison = (DOM2Helper)(Class.forName(liaisonClassName).newInstance());
//org.apache.xpath.XPathContext xctxt = this.getTransformer().getXPathContext();
//xctxt.setDOMHelper(m_liaison);
}
catch (ClassNotFoundException e1)
{
throw new SAXException("XML Liaison class " + liaisonClassName +
" specified but not found", e1);
}
catch (IllegalAccessException e2)
{
throw new SAXException("XML Liaison class " + liaisonClassName +
" found but cannot be loaded", e2);
}
catch (InstantiationException e3)
{
throw new SAXException("XML Liaison class " + liaisonClassName +
" loaded but cannot be instantiated (no empty public constructor?)",
e3);
}
catch (ClassCastException e4)
{
throw new SAXException("XML Liaison class " + liaisonClassName +
" does not implement DOM2Helper", e4);
}
}
/**
* Construct an XSL processor that uses the the given parser liaison.
* As a general rule, you should use XSLTProcessorFactory to create an
* instance of this class and provide access to the instance via the XSLTProcessor interface.
*
* @param XMLParserLiaison A liaison to an XML parser.
*
* @see org.apache.xalan.xpath.xml.XMLParserLiaison
* @see XSLTProcessorFactory
* @see XSLTProcessor
*/
public XSLTEngineImpl(XMLParserLiaison parserLiaison)
throws org.xml.sax.SAXException
{
m_tfactory = TransformerFactory.newInstance();
m_problemListener = new ProblemListenerDefault();
m_liaison = (DOM2Helper)parserLiaison;
// org.apache.xpath.XPathContext xctxt = this.getTransformer().getXPathContext();
//xctxt.setDOMHelper(m_liaison);
}
/**
* Construct an XSLT processor that can call back to the XML parser, in order to handle
* included files and the like.
*
* @param XMLParserLiaison A liaison to an XML parser.
*
* @see org.apache.xalan.xpath.xml.XMLParserLiaison
* @see XSLTProcessorFactory
* @see XSLTProcessor
*/
XSLTEngineImpl(XMLParserLiaison parserLiaison, XPathFactory xpathFactory)
throws SAXException
{
m_tfactory = TransformerFactory.newInstance();
m_problemListener = new ProblemListenerDefault();
m_liaison = (DOM2Helper)parserLiaison;
// org.apache.xpath.XPathContext xctxt = this.getTransformer().getXPathContext();
//xctxt.setDOMHelper(m_liaison);
}
/**
* Get a Liaison class
*/
public XMLParserLiaison createLiaison()
throws org.xml.sax.SAXException
{
return new org.apache.xalan.xpath.xml.XMLParserLiaisonDefault();
}
/**
* Reset the state. This needs to be called after a process() call
* is invoked, if the processor is to be used again.
*/
public void reset()
{
if (m_transformerImpl != null)
m_transformerImpl.reset();
m_stylesheetParams = null;
}
/**
* Transform the source tree to the output in the given
* result tree target. As a general rule, we recommend you use the
* {@link org.apache.xalan.xslt.XSLTProcessor#process(org.apache.xalan.xslt.XSLTInputSource, org.apache.xalan.xslt.XSLTInputSource, org.apache.xalan.xslt.XSLTResultTarget)} method.
* @param inputSource The input source.
* @param stylesheetSource The stylesheet source. May be null if source has a xml-stylesheet PI.
* @param outputTarget The output source tree.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void process( XSLTInputSource inputSource,
XSLTInputSource stylesheetSource,
XSLTResultTarget outputTarget)
throws SAXException
{
try
{
Boolean totalTimeID = new Boolean(true);
pushTime(totalTimeID);
Node sourceTree = null;
Templates templates = null;
if (m_needToEval)
{
Node node = null;
if (null != stylesheetSource)
{
Source ssSource = stylesheetSource.getSourceObject();
if(ssSource instanceof DOMSource)
{
node = ((DOMSource)ssSource).getNode();
}
}
if (null == node)
{
node = new DOM2Helper().createDocument() ;
}
for (int i=0; i< m_evalList.size(); i++)
{
String name = (String)m_evalList.elementAt(i);
String expression = (String)m_stylesheetParams.get(name);
try{
org.apache.xpath.objects.XObject val = org.apache.xpath.XPathAPI.eval(node, expression);
m_stylesheetParams.put(name, val);
}
catch(TransformerException te)
{
throw new SAXException(te);
}
}
m_needToEval = false;
m_evalList = null;
}
sourceTree = getSourceTreeFromInput(inputSource);
if(null != stylesheetSource)
{
try{
templates = m_tfactory.newTemplates(stylesheetSource.getSourceObject());
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
else if( null != inputSource)
{
if(null != sourceTree)
{
String stylesheetURI = null;
Stack hrefs = new Stack();
for(Node child=sourceTree.getFirstChild(); null != child; child=child.getNextSibling())
{
if(Node.PROCESSING_INSTRUCTION_NODE == child.getNodeType())
{
ProcessingInstruction pi = (ProcessingInstruction)child;
if(pi.getNodeName().equals("xml-stylesheet")
|| pi.getNodeName().equals("xml:stylesheet"))
{
boolean isOK = true;
StringTokenizer tokenizer = new StringTokenizer(pi.getNodeValue(), " \t=");
while(tokenizer.hasMoreTokens())
{
if(tokenizer.nextToken().equals("type"))
{
String typeVal = tokenizer.nextToken();
typeVal = typeVal.substring(1, typeVal.length()-1);
if(!typeVal.equals("text/xsl") && !typeVal.equals("text/xml") && !typeVal.equals("application/xml+xslt"))
{
isOK = false;
}
}
}
if(isOK)
{
tokenizer = new StringTokenizer(pi.getNodeValue(), " \t=");
while(tokenizer.hasMoreTokens())
{
if(tokenizer.nextToken().equals("href"))
{
stylesheetURI = tokenizer.nextToken();
stylesheetURI = stylesheetURI.substring(1, stylesheetURI.length()-1);
hrefs.push(stylesheetURI);
}
}
}
}
}
} // end for(int i = 0; i < nNodes; i++)
boolean isRoot = true;
Stylesheet prevStylesheet = null;
while(!hrefs.isEmpty())
{
Stylesheet stylesheet = getStylesheetFromPIURL((String)hrefs.pop(), sourceTree,
(null != inputSource)
? inputSource.getSystemId() : null,
isRoot);
if(false == isRoot)
{
prevStylesheet.setImport((StylesheetComposed)stylesheet);
}
prevStylesheet = stylesheet;
isRoot = false;
}
}
}
else
{
error(XSLTErrorResources.ER_NO_INPUT_STYLESHEET); //"Stylesheet input was not specified!");
}
if(null == templates)
{
if (m_stylesheetRoot != null)
templates = m_stylesheetRoot.getObject();
else
{
error(XSLTErrorResources.ER_FAILED_PROCESS_STYLESHEET); //"Failed to process stylesheet!");
return;
}
}
if(null != templates)
{
try{
m_transformerImpl = (TransformerImpl)templates.newTransformer();
if (m_problemListener != null)
m_transformerImpl.setErrorListener(m_problemListener);
// if (m_liaison != null)
// m_transformerImpl.getXPathContext().setDOMHelper(m_liaison);
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
if (m_stylesheetParams != null)
{
Enumeration keys = m_stylesheetParams.keys();
while (keys.hasMoreElements())
{
String name = (String)keys.nextElement();
Object value = m_stylesheetParams.get(name);
m_transformerImpl.setParameter(name, null, value);
}
}
try{
m_transformerImpl.transform(new DOMSource(sourceTree),
outputTarget.getResultObject());
}
catch (TransformerException te)
{
throw new SAXException(te);
}
if(null != m_diagnosticsPrintWriter)
{
displayDuration("Total time", totalTimeID);
}
}
}
catch(MalformedURLException mue)
{
error(XSLTErrorResources.ERROR0000, new Object[] {mue.getMessage()}, mue);
// throw se;
}
catch(FileNotFoundException fnfe)
{
error(XSLTErrorResources.ERROR0000, new Object[] {fnfe.getMessage()}, fnfe);
// throw se;
}
catch(IOException ioe)
{
error(XSLTErrorResources.ERROR0000, new Object[] {ioe.getMessage()}, ioe);
// throw se;
}
catch(SAXException se)
{
error(XSLTErrorResources.ER_SAX_EXCEPTION, se); //"SAX Exception", se);
// throw se;
}
}
/**
* Bottleneck the creation of the stylesheet for derivation purposes.
*/
public StylesheetRoot createStylesheetRoot(String baseIdentifier)
throws MalformedURLException, FileNotFoundException,
IOException, SAXException
{
try{
if (baseIdentifier == null)
return new StylesheetRoot(this, baseIdentifier);
Source inSource = new XSLTInputSource(baseIdentifier).getSourceObject();
Templates templates = m_tfactory.newTemplates(inSource);
StylesheetRoot stylesheet = new StylesheetRoot((org.apache.xalan.templates.StylesheetRoot)templates);
return stylesheet;
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
/**
* Bottleneck the creation of the stylesheet for derivation purposes.
*/
StylesheetRoot createStylesheetRoot(String baseIdentifier, XSLTInputSource source)
throws MalformedURLException, FileNotFoundException,
IOException, SAXException
{
try{
Source inSource = source.getSourceObject();
Templates templates = m_tfactory.newTemplates(inSource);
StylesheetRoot stylesheet = new StylesheetRoot((org.apache.xalan.templates.StylesheetRoot)templates);
return stylesheet;
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
/**
* Given a URI to an XSL stylesheet,
* Compile the stylesheet into an internal representation.
* This calls reset() before processing if the stylesheet root has been set
* to non-null.
* @param xmldocURLString The URL to the input XML document.
* @return The compiled stylesheet object.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public StylesheetRoot processStylesheet(XSLTInputSource stylesheetSource)
throws SAXException
{
try{
if(null != ((TransformerFactoryImpl)m_tfactory).newTemplatesHandler().getTemplates())
reset();
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
String xslIdentifier = ((null == stylesheetSource) ||
(null == stylesheetSource.getSystemId()))
? "Input XSL" : stylesheetSource.getSystemId();
// In case we have a fragment identifier, go ahead and
// try and parse the XML here.
m_stylesheetRoot = null;
try
{
StylesheetHandler stylesheetProcessor
= new StylesheetHandler((TransformerFactoryImpl)m_tfactory); //this, m_stylesheetRoot);
Source ssSource = stylesheetSource.getSourceObject();
if(ssSource instanceof DOMSource)
{
if(((DOMSource)ssSource).getNode() instanceof StylesheetRoot)
{
m_stylesheetRoot = (StylesheetRoot)((DOMSource)ssSource).getNode();
}
else
{
stylesheetProcessor.setSystemId(stylesheetSource.getSystemId());
TreeWalker tw = new TreeWalker(stylesheetProcessor, new org.apache.xpath.DOM2Helper());
tw.traverse(((DOMSource)ssSource).getNode());
m_stylesheetRoot = new StylesheetRoot(stylesheetProcessor.getStylesheetRoot());
}
}
else
{
if(null != m_liaison)
{
// DOM2Helper liaison = (DOM2Helper)(Class.forName(liaisonClassName).newInstance());
m_liaison.parse(SAXSource.sourceToInputSource(ssSource));
DOMSource source = new DOMSource(m_liaison.getDocument());
Templates templates = m_tfactory.newTemplates(source);
m_stylesheetRoot = new StylesheetRoot(
(org.apache.xalan.templates.StylesheetRoot)templates);
}
else
{
m_stylesheetRoot = createStylesheetRoot(stylesheetSource.getSystemId(), stylesheetSource);
}
addTraceListenersToStylesheet();
stylesheetProcessor.pushStylesheet(m_stylesheetRoot.getObject());
diag("========= Parsing "+xslIdentifier+" ==========");
pushTime(xslIdentifier);
//String liaisonClassName = System.getProperty("org.apache.xalan.source.liaison");
if(null != m_diagnosticsPrintWriter)
displayDuration("Parse of "+xslIdentifier, xslIdentifier);
}
}
catch(Exception e)
{
error(XSLTErrorResources.ER_COULDNT_PARSE_DOC, new Object[] {xslIdentifier}, e); //"Could not parse "+xslIdentifier+" document!", e);
}
return m_stylesheetRoot;
}
/**
* Given a URI to an XSL stylesheet,
* Compile the stylesheet into an internal representation.
* This calls reset() before processing if the stylesheet root has been set
* to non-null.
* @param xmldocURLString The URL to the input XML document.
* @return The compiled stylesheet object.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public StylesheetRoot processStylesheet(String xsldocURLString)
throws SAXException
{
try
{
XSLTInputSource input = new XSLTInputSource(getURLFromString(xsldocURLString, null).toString());
return processStylesheet(input);
}
catch(SAXException se)
{
error(XSLTErrorResources.ER_PROCESSSTYLESHEET_NOT_SUCCESSFUL, se); //"processStylesheet not succesfull!", se);
return null; // shut up compiler
}
}
/**
* Set the stylesheet for this processor. If this is set, then the
* process calls that take only the input .xml will use
* this instead of looking for a stylesheet PI. Also,
* setting the stylesheet is needed if you are going
* to use the processor as a SAX DocumentHandler.
*/
public void setStylesheet(StylesheetRoot stylesheetRoot)
{
m_stylesheetRoot = stylesheetRoot;
org.apache.xalan.templates.StylesheetRoot sr = stylesheetRoot.getObject();
if (m_transformerImpl == null)
m_transformerImpl = (TransformerImpl)sr.newTransformer();
m_transformerImpl.setStylesheet(sr);
if (m_problemListener != null)
m_transformerImpl.setErrorListener(m_problemListener);
}
/**
* Get the current stylesheet for this processor.
*/
public StylesheetRoot getStylesheet()
{
return m_stylesheetRoot;
}
/**
* <meta name="usage" content="internal"/>
* Get the filename of the output document, if it was set.
* This is for use by multiple output documents, to determine
* the base directory for the output document. It needs to
* be set by the caller.
*/
public String getOutputFileName()
{
return m_outputFileName;
}
/**
* <meta name="usage" content="internal"/>
* Set the filename of the output document.
* This is for use by multiple output documents, to determine
* the base directory for the output document. It needs to
* be set by the caller.
*/
public void setOutputFileName(String filename)
{
m_outputFileName = filename;
}
/**
* Given an input source, get the source tree.
*/
public Node getSourceTreeFromInput(XSLTInputSource inputSource)
throws org.xml.sax.SAXException
{
Node sourceTree = null;
String xmlIdentifier = ((null == inputSource) ||
(null == inputSource.getSystemId()))
? "Input XML" : inputSource.getSystemId();
Source iSource = inputSource.getSourceObject();
if(iSource instanceof DOMSource)
{
//if(getXMLProcessorLiaison() instanceof org.apache.xalan.xpath.dtm.DTMLiaison)
// error(XSLTErrorResources.ER_CANT_USE_DTM_FOR_INPUT);
sourceTree = ((DOMSource)iSource).getNode();
}
else
{
// In case we have a fragment identifier, go ahead and
// try and parse the XML here.
try
{
diag("========= Parsing "+xmlIdentifier+" ==========");
pushTime(xmlIdentifier);
//String liaisonClassName = System.getProperty("org.apache.xalan.source.liaison");
if(null != m_liaison)
{
//DOM2Helper liaison = (DOM2Helper)(Class.forName(liaisonClassName).newInstance());
m_liaison.parse(SAXSource.sourceToInputSource(iSource));
if(null != m_diagnosticsPrintWriter)
displayDuration("Parse of "+xmlIdentifier, xmlIdentifier);
sourceTree = m_liaison.getDocument();
}
else
{
try
{
// Use an implementation of the JAVA API for XML Parsing 1.0 to
// create a DOM Document node to contain the result.
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
dfactory.setValidating(false);
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
sourceTree = docBuilder.parse(xmlIdentifier);
}
catch (ParserConfigurationException pce)
{
error(XSLTErrorResources.ER_COULDNT_PARSE_DOC, new Object[] {xmlIdentifier}, pce);
}
}
}
catch(Exception e)
{
// Unwrap exception
if((e instanceof SAXException) && (null != ((SAXException)e).getException()))
{
// ((SAXException)e).getException().printStackTrace();
e = ((SAXException)e).getException();
}
sourceTree = null; // shutup compiler
error(XSLTErrorResources.ER_COULDNT_PARSE_DOC, new Object[] {xmlIdentifier}, e); //"Could not parse "+xmlIdentifier+" document!", e);
}
}
return sourceTree;
}
/**
* Get Stylesheet from PI URL
*
* @param xslURLString a valid URI to an XSL stylesheet.
* @param fragbase Document fragment Node.
* @param xmlBaseIdent Base URI to resolve stylesheet URL
* @param isRoot Flag indicating if root node
*/
Stylesheet getStylesheetFromPIURL(String xslURLString, Node fragBase,
String xmlBaseIdent, boolean isRoot)
throws SAXException,
MalformedURLException,
FileNotFoundException,
IOException
{
Stylesheet stylesheet = null;
String[] stringHolder =
{
null};
xslURLString = xslURLString.trim();
int fragIndex = xslURLString.indexOf('#');
String fragID = null;
Document stylesheetDoc;
if(fragIndex == 0)
{
diag("Locating stylesheet from fragment identifier...");
fragID = xslURLString.substring(1);
// Try a bunch of really ugly stuff to find the fragment.
// What's the right way to do this?
// Create a XPath parser.
XPathParser parser = new XPathParser((ErrorListener)m_problemListener.getErrorHandler(), null);
XPathContext xpathContext = new XPathContext();
PrefixResolverDefault nsNode = new PrefixResolverDefault(fragBase); //xpathContext.getNamespaceContext();
NodeIterator nl = null;
// Create the XPath object.
try{
XPath xpath = new XPath(fragID, null, nsNode, XPath.MATCH);
Compiler compiler = new Compiler();
// Parse the xpath
parser.initXPath(compiler, "id("+fragID+")", nsNode);
org.apache.xpath.objects.XObject xobj = xpath.execute(xpathContext, fragBase, nsNode);
nl = new org.apache.xml.dtm.ref.DTMNodeIterator(xobj.iter());
if(nl.nextNode() == null)
{
// xobj = Stylesheet.evalXPathStr(getExecContext(), "//*[@id='"+fragID+"']", fragBase, nsNode);
// Create the XPath object.
xpath = new XPath(fragID, null, nsNode, XPath.MATCH);
// Parse the xpath
parser.initXPath(compiler, "//*[@id='"+fragID+"']", nsNode);
xobj = xpath.execute(xpathContext, fragBase, nsNode);
nl = new org.apache.xml.dtm.ref.DTMNodeIterator(xobj.iter());
if(nl.nextNode() == null)
{
// xobj = Stylesheet.evalXPathStr(getExecContext(), "//*[@name='"+fragID+"']", fragBase, nsNode);
// Create the XPath object.
xpath = new XPath(fragID, null, nsNode, XPath.MATCH);
// Parse the xpath
parser.initXPath(compiler, "//*[@name='"+fragID+"']", nsNode);
xobj = xpath.execute(xpathContext, fragBase, nsNode);
nl = new org.apache.xml.dtm.ref.DTMNodeIterator(xobj.iter());
if(nl.nextNode() == null)
{
// Well, hell, maybe it's an XPath...
// xobj = Stylesheet.evalXPathStr(getExecContext(), fragID, fragBase, nsNode);
// Create the XPath object.
//((StylesheetHandler)( m_processor.getTemplatesBuilder())).getLocator()
xpath = new XPath(fragID, null, nsNode, XPath.MATCH);
// Parse the xpath
parser.initXPath(compiler, fragID, nsNode);
xobj = xpath.execute(xpathContext, fragBase, nsNode);
nl = new org.apache.xml.dtm.ref.DTMNodeIterator(xobj.iter());
}
}
}
}
catch (TransformerException te)
{
throw new SAXException(te);
}
if(nl.nextNode() == null)
{
error(XSLTErrorResources.ER_COULDNT_FIND_FRAGMENT, new Object[] {fragID}); //"Could not find fragment: "+fragID);
}
// Use previous because the previous call moved the pointer.
// or should we use getRoot??
Node frag = nl.previousNode(); //.item(0);
if(Node.ELEMENT_NODE == frag.getNodeType())
{
pushTime(frag);
if(isRoot)
{
m_stylesheetRoot = createStylesheetRoot(stringHolder[0]);
stylesheet = m_stylesheetRoot.getObject();
}
else
{
//stylesheet = new Stylesheet(m_stylesheetRoot);
// stylesheet = ((StylesheetHandler)(m_processor.getTemplatesBuilder())).getStylesheetRoot();
try{
Source source = new XSLTInputSource(fragID).getSourceObject();
Templates templates = m_tfactory.newTemplates(source);
stylesheet = (org.apache.xalan.templates.StylesheetRoot)templates;
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
addTraceListenersToStylesheet();
try{
StylesheetHandler stylesheetProcessor
= new StylesheetHandler((TransformerFactoryImpl)m_tfactory);
stylesheetProcessor.pushStylesheet(stylesheet);
TreeWalker tw = new TreeWalker(stylesheetProcessor, new org.apache.xpath.DOM2Helper());
tw.traverse(frag);
displayDuration("Setup of "+xslURLString, frag);
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
else
{
stylesheetDoc = null;
error(XSLTErrorResources.ER_NODE_NOT_ELEMENT, new Object[] {fragID}); //"Node pointed to by fragment identifier was not an element: "+fragID);
}
}
else
{
// TODO: Use Reader here??
// hmmm.. for now I'll rely on the XML parser to handle
// fragment URLs.
diag(XSLMessages.createMessage(XSLTErrorResources.WG_PARSING_AND_PREPARING, new Object[] {xslURLString})); //"========= Parsing and preparing "+xslURLString+" ==========");
pushTime(xslURLString);
URL xslURL = getURLFromString(xslURLString, xmlBaseIdent);
XSLTInputSource inputSource = new XSLTInputSource(xslURL.toString());
if(isRoot)
{
if(null != m_liaison)
{
try{
m_liaison.parse(SAXSource.sourceToInputSource(inputSource.getSourceObject()));
DOMSource source = new DOMSource(m_liaison.getDocument());
Templates templates = m_tfactory.newTemplates(source);
m_stylesheetRoot = new StylesheetRoot(
(org.apache.xalan.templates.StylesheetRoot)templates);
}
catch (TransformerException tce)
{
throw new SAXException(tce);
}
}
else
{
m_stylesheetRoot = createStylesheetRoot(xslURLString);
}
stylesheet = m_stylesheetRoot.getObject();
}
else
{
stylesheet = new Stylesheet(m_stylesheetRoot.getObject());
}
addTraceListenersToStylesheet();
try{
org.apache.xalan.processor.StylesheetHandler stylesheetProcessor
= new StylesheetHandler((TransformerFactoryImpl)m_tfactory); //this, stylesheet);
stylesheetProcessor.pushStylesheet(stylesheet);
// new StylesheetHandler(this, stylesheet);
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
//m_parserLiaison.setDocumentHandler(stylesheetProcessor);
//m_parserLiaison.parse(inputSource);
displayDuration("Parsing and init of "+xslURLString, xslURLString);
}
return stylesheet;
}
/**
* Take a user string and try and parse XML, and also return
* the url.
* @exception XSLProcessorException thrown if the active ProblemListener and XPathContext decide
* the error condition is severe enough to halt processing.
*/
public static URL getURLFromString(String urlString, String base)
throws SAXException
{
String origURLString = urlString;
String origBase = base;
// System.out.println("getURLFromString - urlString: "+urlString+", base: "+base);
Object doc;
URL url = null;
int fileStartType = 0;
try
{
if(null != base)
{
if(base.toLowerCase().startsWith("file:/"))
{
fileStartType = 1;
}
else if(base.toLowerCase().startsWith("file:"))
{
fileStartType = 2;
}
}
boolean isAbsoluteURL;
// From http://www.ics.uci.edu/pub/ietf/uri/rfc1630.txt
// A partial form can be distinguished from an absolute form in that the
// latter must have a colon and that colon must occur before any slash
// characters. Systems not requiring partial forms should not use any
// unencoded slashes in their naming schemes. If they do, absolute URIs
// will still work, but confusion may result.
int indexOfColon = urlString.indexOf(':');
int indexOfSlash = urlString.indexOf('/');
if((indexOfColon != -1) && (indexOfSlash != -1) && (indexOfColon < indexOfSlash))
{
// The url (or filename, for that matter) is absolute.
isAbsoluteURL = true;
}
else
{
isAbsoluteURL = false;
}
if(isAbsoluteURL || (null == base) || (base.length() == 0))
{
try
{
url = new URL(urlString);
}
catch (MalformedURLException e) {}
}
// The Java URL handling doesn't seem to handle relative file names.
else if(!((urlString.charAt(0) == '.') || (fileStartType > 0)))
{
try
{
URL baseUrl = new URL(base);
url = new URL(baseUrl, urlString);
}
catch (MalformedURLException e)
{
}
}
if(null == url)
{
// Then we're going to try and make a file URL below, so strip
// off the protocol header.
if(urlString.toLowerCase().startsWith("file:/"))
{
urlString = urlString.substring(6);
}
else if(urlString.toLowerCase().startsWith("file:"))
{
urlString = urlString.substring(5);
}
}
if((null == url) && ((null == base) || (fileStartType > 0)))
{
if(1 == fileStartType)
{
if(null != base)
base = base.substring(6);
fileStartType = 1;
}
else if(2 == fileStartType)
{
if(null != base)
base = base.substring(5);
fileStartType = 2;
}
File f = new File(urlString);
if(!f.isAbsolute() && (null != base))
{
// String dir = f.isDirectory() ? f.getAbsolutePath() : f.getParent();
// System.out.println("prebuiltUrlString (1): "+base);
StringTokenizer tokenizer = new StringTokenizer(base, "\\/");
String fixedBase = null;
while(tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (null == fixedBase)
{
// Thanks to Rick Maddy for the bug fix for UNIX here.
if (base.charAt(0) == '\\' || base.charAt(0) == '/')
{
fixedBase = File.separator + token;
}
else
{
fixedBase = token;
}
}
else
{
fixedBase+= File.separator + token;
}
}
// System.out.println("rebuiltUrlString (1): "+fixedBase);
f = new File(fixedBase);
String dir = f.isDirectory() ? f.getAbsolutePath() : f.getParent();
// System.out.println("dir: "+dir);
// System.out.println("urlString: "+urlString);
// f = new File(dir, urlString);
// System.out.println("f (1): "+f.toString());
// urlString = f.getAbsolutePath();
f = new File(urlString);
boolean isAbsolute = f.isAbsolute()
|| (urlString.charAt( 0 ) == '\\')
|| (urlString.charAt( 0 ) == '/');
if(!isAbsolute)
{
// Getting more and more ugly...
if(dir.charAt( dir.length()-1 ) != File.separator.charAt(0) &&
urlString.charAt( 0 ) != File.separator.charAt(0))
{
urlString = dir + File.separator + urlString;
}
else
{
urlString = dir + urlString;
}
// System.out.println("prebuiltUrlString (2): "+urlString);
tokenizer = new StringTokenizer(urlString, "\\/");
String rebuiltUrlString = null;
while(tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (null == rebuiltUrlString)
{
// Thanks to Rick Maddy for the bug fix for UNIX here.
if (urlString.charAt(0) == '\\' || urlString.charAt(0) == '/')
{
rebuiltUrlString = File.separator + token;
}
else
{
rebuiltUrlString = token;
}
}
else
{
rebuiltUrlString+= File.separator + token;
}
}
// System.out.println("rebuiltUrlString (2): "+rebuiltUrlString);
if(null != rebuiltUrlString)
urlString = rebuiltUrlString;
}
// System.out.println("fileStartType: "+fileStartType);
if(1 == fileStartType)
{
if (urlString.charAt(0) == '/')
{
urlString = "file://"+urlString;
}
else
{
urlString = "file:/"+urlString;
}
}
else if(2 == fileStartType)
{
urlString = "file:"+urlString;
}
try
{
// System.out.println("Final before try: "+urlString);
url = new URL(urlString);
}
catch (MalformedURLException e)
{
// System.out.println("Error trying to make URL from "+urlString);
}
}
}
if(null == url)
{
// The sun java VM doesn't do this correctly, but I'll
// try it here as a second-to-last resort.
if((null != origBase) && (origBase.length() > 0))
{
try
{
URL baseURL = new URL(origBase);
// System.out.println("Trying to make URL from "+origBase+" and "+origURLString);
url = new URL(baseURL, origURLString);
// System.out.println("Success! New URL is: "+url.toString());
}
catch (MalformedURLException e)
{
// System.out.println("Error trying to make URL from "+origBase+" and "+origURLString);
}
}
if(null == url)
{
try
{
String lastPart;
if(null != origBase)
{
File baseFile = new File(origBase);
if(baseFile.isDirectory())
{
lastPart = new File(baseFile, urlString).getAbsolutePath ();
}
else
{
String parentDir = baseFile.getParent();
lastPart = new File(parentDir, urlString).getAbsolutePath ();
}
}
else
{
lastPart = new File (urlString).getAbsolutePath ();
}
// Hack
// if((lastPart.charAt(0) == '/') && (lastPart.charAt(2) == ':'))
// lastPart = lastPart.substring(1, lastPart.length() - 1);
String fullpath;
if (lastPart.charAt(0) == '\\' || lastPart.charAt(0) == '/')
{
fullpath = "file://" + lastPart;
}
else
{
fullpath = "file:" + lastPart;
}
url = new URL(fullpath);
}
catch (MalformedURLException e2)
{
throw new SAXException("Cannot create url for: " + urlString, e2 );
//XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CREATE_URL, new Object[]{urlString}),e2); //"Cannot create url for: " + urlString, e2 );
}
}
}
}
catch(SecurityException se)
{
try
{
url = new URL("http://xml.apache.org/xslt/"+java.lang.Math.random()); // dummy
}
catch (MalformedURLException e2)
{
// I give up
}
}
// System.out.println("url: "+url.toString());
return url;
}
/**
* Add a trace listener for the purposes of debugging and diagnosis.
* @param tl Trace listener to be added.
*/
void addTraceListenersToStylesheet()
throws SAXException
{
/*try
{
TraceManager tm = m_transformerImpl.getTraceManager();
if(tm.hasTraceListeners)
{
int nListeners = tm.size();
for(int i = 0; i < nListeners; i++)
{
TraceListener tl = (TraceListener)m_traceListeners.elementAt(i);
if(null != m_stylesheetRoot)
m_stylesheetRoot.addTraceListener(tl);
}
}
}
catch(TooManyListenersException tmle)
{
throw new SAXException(XSLMessages.createMessage(XSLTErrorResources.ER_TOO_MANY_LISTENERS, null),tmle ); //"addTraceListenersToStylesheet - TooManyListenersException", tmle);
}*/
}
/**
* Warn the user of an problem.
* This is public for access by extensions.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void message(String msg)
throws SAXException
{
message(null, null, msg);
}
/**
* Warn the user of an problem.
* This is public for access by extensions.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void message(Node styleNode, Node sourceNode, String msg)
throws SAXException
{
m_problemListener.message(msg);
}
/**
* <meta name="usage" content="internal"/>
* Warn the user of an problem.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void warn(int msg)
throws SAXException
{
warn(null, null, msg, null);
}
/**
* <meta name="usage" content="internal"/>
* Warn the user of an problem.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void warn(int msg, Object[] args)
throws SAXException
{
warn(null, null, msg, args);
}
/**
* <meta name="usage" content="internal"/>
* Warn the user of an problem.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void warn(Node styleNode, Node sourceNode, int msg)
throws SAXException
{
warn(styleNode, sourceNode, msg, null);
}
/**
* <meta name="usage" content="internal"/>
* Warn the user of an problem.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void warn(Node styleNode, Node sourceNode, int msg, Object args[])
throws SAXException
{
Exception e = null;
String fmsg = m_XSLMessages.createWarning(msg, args);
SourceLocator locator = null;
try{
locator = ((StylesheetHandler)(((TransformerFactoryImpl)this.m_tfactory).newTemplatesHandler())).getLocator();
}
catch (TransformerConfigurationException tce)
{
}
DefaultErrorHandler handler;
if (m_problemListener == null)
handler = (DefaultErrorHandler)m_tfactory.getErrorListener();
else
handler = (DefaultErrorHandler)m_problemListener.getErrorHandler();
TransformerException te = (null == e) ? new TransformerException(fmsg, locator) :
new TransformerException(fmsg, locator, e);
if(null != handler)
{
try{
handler.warning(te);
}
catch (TransformerException te2)
{
throw new SAXException(te2);
}
}
else
throw new SAXException(te);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(String msg)
throws SAXException
{
Exception e = null;
SourceLocator locator = null;
try{
locator = ((StylesheetHandler)(((TransformerFactoryImpl)this.m_tfactory).newTemplatesHandler())).getLocator();
}
catch (TransformerConfigurationException tce)
{
}
DefaultErrorHandler handler;
if (m_problemListener == null)
handler = (DefaultErrorHandler)m_tfactory.getErrorListener();
else
handler = (DefaultErrorHandler)m_problemListener.getErrorHandler();
TransformerException te = (null == e) ? new TransformerException(msg, locator) :
new TransformerException(msg, locator, e);
if(null != handler)
{
try{
handler.fatalError(te);
}
catch (TransformerException te2)
{
throw new SAXException(te2);
}
}
else
throw new SAXException(te);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(int msg)
throws SAXException
{
error(null, null, msg, null);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(int msg, Object[] args)
throws SAXException
{
error(null, null, msg, args);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(int msg, Exception e)
throws SAXException
{
error(msg, null, e);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(int msg, Object args[], Exception e)
throws SAXException
{
String fmsg = m_XSLMessages.createMessage(msg, args);
SourceLocator locator = null;
try{
locator = ((StylesheetHandler)(((TransformerFactoryImpl)this.m_tfactory).newTemplatesHandler())).getLocator();
}
catch (TransformerConfigurationException tce)
{
}
DefaultErrorHandler handler;
if (m_problemListener == null)
handler = (DefaultErrorHandler)m_tfactory.getErrorListener();
else
handler = (DefaultErrorHandler)m_problemListener.getErrorHandler();
TransformerException te = (null == e) ? new TransformerException(fmsg, locator) :
new TransformerException(fmsg, locator, e);
if(null != handler)
{
try{
handler.fatalError(te);
}
catch (TransformerException te2)
{
throw new SAXException(te2);
}
}
else
throw new SAXException(te);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(Node styleNode, Node sourceNode, int msg)
throws SAXException
{
error(styleNode, sourceNode, msg, null);
}
/**
* <meta name="usage" content="internal"/>
* Tell the user of an error, and probably throw an
* exception.
* @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
* the error condition is severe enough to halt processing.
*/
public void error(Node styleNode, Node sourceNode, int msg, Object args[])
throws SAXException
{
Exception e = null;
String fmsg = m_XSLMessages.createMessage(msg, args);
SourceLocator locator = null;
try{
locator = ((StylesheetHandler)(((TransformerFactoryImpl)this.m_tfactory).newTemplatesHandler())).getLocator();
}
catch (TransformerConfigurationException tce)
{
}
DefaultErrorHandler handler;
if (m_problemListener == null)
handler = (DefaultErrorHandler)m_tfactory.getErrorListener();
else
handler = (DefaultErrorHandler)m_problemListener.getErrorHandler();
TransformerException te = (null == e) ? new TransformerException(fmsg, locator) :
new TransformerException(fmsg, locator, e);
if(null != handler)
{
try{
handler.fatalError(te);
}
catch (TransformerException te2)
{
throw new SAXException(te2);
}
}
else
throw new SAXException(te);
}
/**
* Mark the time, so that displayDuration can later
* display the elapse.
*/
void pushTime(Object key)
{
if(null != key)
{
m_durationsTable.put(key, new Long(System.currentTimeMillis()));
}
}
/**
* Returns the duration since pushTime was called,
* in milliseconds.
*/
long popDuration(Object key)
{
long millisecondsDuration = 0;
if(null != key)
{
long start = ((Long)m_durationsTable.get(key)).longValue();
long stop = System.currentTimeMillis();
millisecondsDuration = stop - start;
m_durationsTable.remove(key);
}
return millisecondsDuration;
}
/**
* Display the duration since pushTime was called.
*/
protected void displayDuration(String info, Object key)
{
long millisecondsDuration = 0;
if(null != key)
{
long start = ((Long)m_durationsTable.get(key)).longValue();
long stop = System.currentTimeMillis();
millisecondsDuration = stop - start;
if(null != m_diagnosticsPrintWriter)
{
m_diagnosticsPrintWriter.println(info + " took " + millisecondsDuration + " milliseconds");
}
m_durationsTable.remove(key);
}
}
/**
* If this is set, diagnostics will be
* written to the m_diagnosticsPrintWriter stream. If
* the value is null, then diagnostics will be turned
* off.
*/
public void setDiagnosticsOutput(java.io.OutputStream out)
{
setDiagnosticsOutput(new PrintWriter(out));
}
/**
* If this is set, diagnostics will be
* written to the m_diagnosticsPrintWriter stream. If
* the value is null, then diagnostics will be turned
* off.
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
m_diagnosticsPrintWriter = pw;
/* if(getProblemListener() instanceof ProblemListenerDefault)
{
((ProblemListenerDefault)getProblemListener()).setDiagnosticsOutput(pw);
}*/
}
/**
* Bottleneck output of diagnostics.
*/
protected void diag(String s)
{
if(null != m_diagnosticsPrintWriter)
{
m_diagnosticsPrintWriter.println(s);
}
}
/**
* If this is set to true, simple traces of
* template calls are made.
*/
public void setTraceTemplates(boolean b)
{
m_traceTemplates = b;
}
/**
* If this is set to true, simple traces of
* template calls are made.
*/
public void setTraceSelect(boolean b)
{
m_traceSelects = b;
}
/**
* If this is set to true, debug diagnostics about
* template children as they are being constructed
* will be written to the m_diagnosticsPrintWriter
* stream. diagnoseTemplateChildren is false by
* default.
*/
public void setTraceTemplateChildren(boolean b)
{
m_traceTemplateChildren = b;
}
//
// Lexical handler interface
//
/**
* Report the start of DTD declarations, if any.
*
* <p>Any declarations are assumed to be in the internal subset
* unless otherwise indicated by a {@link #startEntity startEntity}
* event.</p>
*
* <p>Note that the start/endDTD events will appear within
* the start/endDocument events from ContentHandler and
* before the first startElement event.</p>
*
* @param name The document type name.
* @param publicId The declared public identifier for the
* external DTD subset, or null if none was declared.
* @param systemId The declared system identifier for the
* external DTD subset, or null if none was declared.
* @exception SAXException The application may raise an
* exception.
* @see #endDTD
* @see #startEntity
*/
public void startDTD (String name, String publicId, String systemId)
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().startDTD(name, publicId, systemId);
}
/**
* Report the end of DTD declarations.
*
* @exception SAXException The application may raise an exception.
* @see #startDTD
*/
public void endDTD ()
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().endDTD();
}
public void startEntity (String name)
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().startEntity (name);
}
/**
* Report the end of an entity.
*
* @param name The name of the entity that is ending.
* @exception SAXException The application may raise an exception.
* @see #startEntity
*/
public void endEntity (String name)
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().endEntity (name);
}
/**
* Report the start of a CDATA section.
*
* <p>The contents of the CDATA section will be reported through
* the regular {@link org.xml.sax.ContentHandler#characters
* characters} event.</p>
*
* @exception SAXException The application may raise an exception.
* @see #endCDATA
*/
public void startCDATA ()
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().startCDATA();
}
/**
* Report the end of a CDATA section.
*
* @exception SAXException The application may raise an exception.
* @see #startCDATA
*/
public void endCDATA ()
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().endCDATA();
}
/**
* Report an XML comment anywhere in the document.
*
* <p>This callback will be used for comments inside or outside the
* document element, including comments in the external DTD
* subset (if read).</p>
*
* @param ch An array holding the characters in the comment.
* @param start The starting position in the array.
* @param length The number of characters to use from the array.
* @exception SAXException The application may raise an exception.
*/
public void comment (char ch[], int start, int length)
throws SAXException
{
if (m_transformerImpl != null && m_transformerImpl.getInputLexicalHandler() != null)
m_transformerImpl.getInputLexicalHandler().comment (ch, start, length);
}
// DocumentHandler interface
/**
* Receive an object for locating the origin of SAX document events.
*
* <p>SAX parsers are strongly encouraged (though not absolutely
* required) to supply a locator: if it does so, it must supply
* the locator to the application by invoking this method before
* invoking any of the other methods in the DocumentHandler
* interface.</p>
*
* <p>The locator allows the application to determine the end
* position of any document-related event, even if the parser is
* not reporting an error. Typically, the application will
* use this information for reporting its own errors (such as
* character content that does not match an application's
* business rules). The information returned by the locator
* is probably not sufficient for use with a search engine.</p>
*
* <p>Note that the locator will return correct information only
* during the invocation of the events in this interface. The
* application should not attempt to use it at any other time.</p>
*
* @param locator An object that can return the location of
* any SAX document event.
* @see org.xml.sax.Locator
*/
public void setDocumentLocator (Locator locator)
{}
/**
* Receive notification of the beginning of a document.
*
* <p>The SAX parser will invoke this method only once, before any
* other methods in this interface or in DTDHandler (except for
* setDocumentLocator).</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void startDocument ()
throws SAXException
{
if (m_documentHandler != null)
m_documentHandler.startDocument();
else if (m_transformerImpl != null)
m_transformerImpl.getInputContentHandler().startDocument();
//m_transformerImpl.getResultTreeHandler().startDocument();
}
/**
* Receive notification of the end of a document.
*
* <p>The SAX parser will invoke this method only once, and it will
* be the last method invoked during the parse. The parser shall
* not invoke this method until it has either abandoned parsing
* (because of an unrecoverable error) or reached the end of
* input.</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void endDocument ()
throws SAXException
{
if (m_documentHandler != null)
m_documentHandler.endDocument();
else if (m_transformerImpl != null)
m_transformerImpl.getInputContentHandler().endDocument();
//m_transformerImpl.getResultTreeHandler().endDocument();
}
/**
* Receive notification of the beginning of an element.
*
* <p>The Parser will invoke this method at the beginning of every
* element in the XML document; there will be a corresponding
* endElement() event for every startElement() event (even when the
* element is empty). All of the element's content will be
* reported, in order, before the corresponding endElement()
* event.</p>
*
* <p>If the element name has a namespace prefix, the prefix will
* still be attached. Note that the attribute list provided will
* contain only attributes with explicit values (specified or
* defaulted): #IMPLIED attributes will be omitted.</p>
*
* @param name The element type name.
* @param atts The attributes attached to the element, if any.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #endElement
* @see org.xml.sax.AttributeList
*/
public void startElement (String name, AttributeList atts)
throws SAXException
{
if (m_documentHandler == null)
{
m_documentHandler = new ParserAdapter(new org.apache.xerces.parsers.SAXParser());
if (m_transformerImpl != null)
{
((ParserAdapter)m_documentHandler).setContentHandler(m_transformerImpl.getInputContentHandler());
}
/* else if (m_transformerImpl != null)
{
int index = name.indexOf(":");
if (index < 0 )
m_transformerImpl.getInputContentHandler().startElement(null, name, name, (Attributes)atts);
//getResultTreeHandler().startElement(null, name, name, (Attributes)atts);
else
m_transformerImpl.getInputContentHandler().startElement(name.substring(0,index), name.substring(index+1), name, (Attributes)atts);
//m_transformerImpl.getResultTreeHandler().startElement(name.substring(0,index), name.substring(index+1), name, (Attributes)atts);
*/
}
m_documentHandler.startElement(name, atts);
}
/**
* Receive notification of the end of an element.
*
* <p>The SAX parser will invoke this method at the end of every
* element in the XML document; there will be a corresponding
* startElement() event for every endElement() event (even when the
* element is empty).</p>
*
* <p>If the element name has a namespace prefix, the prefix will
* still be attached to the name.</p>
*
* @param name The element type name
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void endElement (String name)
throws SAXException
{
if (m_documentHandler == null)
{
m_documentHandler = new ParserAdapter(new org.apache.xerces.parsers.SAXParser());
if (m_transformerImpl != null)
{
((ParserAdapter)m_documentHandler).setContentHandler(m_transformerImpl.getInputContentHandler());
}
/* else if (m_transformerImpl != null)
{
int index = name.indexOf(":");
if (index < 0 )
m_transformerImpl.getInputContentHandler().endElement(null, name, name);
//m_transformerImpl.getResultTreeHandler().endElement(null, name, name);
else
m_transformerImpl.getInputContentHandler().endElement(name.substring(0,index), name.substring(index+1), name);
//m_transformerImpl.getResultTreeHandler().endElement(name.substring(0,index), name.substring(index+1), name);
*/
}
m_documentHandler.endElement(name);
}
/**
* Receive notification of character data.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*/
public void characters (char ch[], int start, int length)
throws SAXException
{
if (m_documentHandler != null)
m_documentHandler.characters(ch, start, length);
else if (m_transformerImpl != null)
m_transformerImpl.getInputContentHandler().characters(ch, start, length);
//m_transformerImpl.getResultTreeHandler().characters(ch, start, length);
}
/**
* Receive notification of ignorable whitespace in element content.
*
* <p>Validating Parsers must use this method to report each chunk
* of ignorable whitespace (see the W3C XML 1.0 recommendation,
* section 2.10): non-validating parsers may also use this method
* if they are capable of parsing and using content models.</p>
*
* <p>SAX parsers may return all contiguous whitespace in a single
* chunk, or they may split it into several chunks; however, all of
* the characters in any single event must come from the same
* external entity, so that the Locator provides useful
* information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #characters
*/
public void ignorableWhitespace (char ch[], int start, int length)
throws SAXException
{
if (m_documentHandler != null)
m_documentHandler.ignorableWhitespace(ch, start, length);
else if (m_transformerImpl != null)
m_transformerImpl.getInputContentHandler().ignorableWhitespace(ch, start, length);
//m_transformerImpl.getResultTreeHandler().ignorableWhitespace(ch, start, length);
}
/**
* Receive notification of a processing instruction.
*
* <p>The Parser will invoke this method once for each processing
* instruction found: note that processing instructions may occur
* before or after the main document element.</p>
*
* <p>A SAX parser should never report an XML declaration (XML 1.0,
* section 2.8) or a text declaration (XML 1.0, section 4.3.1)
* using this method.</p>
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none was supplied.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void processingInstruction (String target, String data)
throws SAXException
{
if (m_documentHandler != null)
m_documentHandler.processingInstruction(target, data);
else if (m_transformerImpl != null)
m_transformerImpl.getInputContentHandler().processingInstruction(target, data);
//m_transformerImpl.getResultTreeHandler().processingInstruction(target, data);
}
// Implement XSLTProcessor
/**
* Set the output stream. Required when the XSLTProcessor is being used
* as a SAX DocumentHandler.
*/
public void setOutputStream(java.io.OutputStream os)
{
TransformerHandlerImpl handler = new TransformerHandlerImpl(m_transformerImpl, false, null);
handler.setResult(new StreamResult(os));
}
/**
* Convenience function to create an XString.
* @param s A valid string.
* @return An XString object.
*/
public XString createXString(String s)
{
return new XString(s);
}
/**
* Convenience function to create an XObject.
* @param o Any java object.
* @return An XObject object.
*/
public XObject createXObject(Object o)
{
return new XObject(o);
}
/**
* Convenience function to create an XNumber.
* @param d Any double number.
* @return An XNumber object.
*/
public XNumber createXNumber(double d)
{
return new XNumber(d);
}
/**
* Convenience function to create an XBoolean.
* @param b boolean value.
* @return An XBoolean object.
*/
public XBoolean createXBoolean(boolean b)
{
return new XBoolean(b);
}
/**
* Convenience function to create an XNodeSet.
* @param nl A NodeList object.
* @return An XNodeSet object.
*/
public XNodeSet createXNodeSet(NodeList nl)
{
return new XNodeSet(nl);
}
/**
* Convenience function to create an XNodeSet from a node.
* @param n A DOM node.
* @return An XNodeSet object.
*/
public XNodeSet createXNodeSet(Node n)
{
return new XNodeSet(n);
}
/**
* Convenience function to create an XNull.
* @return An XNull object.
*/
public XNull createXNull()
{
return new XNull();
}
/**
* Get the XMLParserLiaison that this processor uses.
*/
public XMLParserLiaison getXMLProcessorLiaison()
{
return (XMLParserLiaison)m_liaison;
}
/**
* Get the preferred stylesheet for the XSLTInputSource XML document,
* as identified by the xml-stylesheet PI, and matching the media and
* charset criteria. See <a href="http://www.w3.org/TR/xml-stylesheet/">
* Associating Style Sheets with XML documents</a>.
* Does not yet handle the LINK REL="stylesheet" syntax.
*
* @param media The media attribute to be matched. May be null, in which
* case the prefered stylesheet will be used (i.e., alternate = no).
* @param title The value of the title attribute to match. May be null.
* @param charset The value of the charset attribute to match. May be null.
* @returns StylesheetSpec extends XSLTInputSource extedns SAX InputSource; the return value
* can be passed to the processStylesheet method.
*/
public StylesheetSpec getAssociatedStylesheet(XSLTInputSource source,
String media,
String charset)
throws SAXException
{
/*InputSource[]in = m_processor.getAssociatedStylesheets(source, media, null, charset);
if (in.length >0)
return (StylesheetSpec)in[0];
else
return null; */
try{
Source s = m_tfactory.getAssociatedStylesheet(source.getSourceObject(), media, null, charset);
return (StylesheetSpec)s;
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
/**
* Get a list of stylesheet specifications for the XSLTInputSource XML document,
* as identified by the xml-stylesheet PI, and matching the media and
* charset criteria. See <a href="http://www.w3.org/TR/xml-stylesheet/">
* Associating Style Sheets with XML documents</a>.
* Does not yet handle the LINK REL="stylesheet" syntax.
*
* @param media The media attribute to be matched. May be null, in which
* case the prefered stylesheet will be used (i.e., alternate = no).
* @param title The value of the title attribute to match. May be null.
* @param charset The value of the charset attribute to match. May be null.
* @returns list of StylesheetSpecs (extend XSLTInputSources extend SAX InputSources; a
* list member may be passsed to the processStylesheet method.
*/
public Vector getAssociatedStylesheets(XSLTInputSource source,
String media,
String charset)
throws SAXException
{
try{
Source s = m_tfactory.getAssociatedStylesheet(source.getSourceObject(), media, null, charset);
Vector v = new Vector();
//for (int i = 0; i< in.length; i++)
v.addElement((StylesheetSpec)s);
return v;
}
catch (TransformerConfigurationException tce)
{
throw new SAXException(tce);
}
}
/**
* Submit a top-level stylesheet parameter. This value can
* be evaluated in the stylesheet via xsl:param-variable.
* @param key The name of the param.
* @param value An XObject that will be used.
*/
public void setStylesheetParam(String key, XObject value)
{
setParameter(key, value.object());
}
/**
* Set a top-level stylesheet parameter. This value can
* be evaluated via xsl:param-variable. Note that the value
* passed is an expression, and not a string. This means that
* setStylesheetParam("foo", "hello"); will look for the
* element "hello". If you want to pass a string, you'll
* need to put quotes around it:
* setStylesheetParam("foo", "'hello'"); will look for the
* @param key The name of the param.
* @param expression An expression that will be evaluated.
*/
public void setStylesheetParam(String key, String expression)
{
if (m_evalList == null)
m_evalList = new Vector();
if (!m_evalList.contains(key))
m_evalList.addElement(key);
setParameter(key, expression);
m_needToEval = true;
}
/**
* Set a top-level stylesheet parameter. This value can
* be evaluated via xsl:param-variable. Note that the value
* passed is an expression, and not a string. This means that
* setStylesheetParam("foo", "hello"); will look for the
* element "hello". If you want to pass a string, you'll
* need to put quotes around it:
* setStylesheetParam("foo", "'hello'"); will look for the
* @param key The name of the param.
* @param expression An expression that will be evaluated.
*/
public void setParameter(String key, Object value)
{
if (m_stylesheetParams == null)
m_stylesheetParams = new Hashtable();
m_stylesheetParams.put(key, value);
}
/**
* Get the current FormatterListener (SAX DocumentHandler), or null if none has been set.
*/
public DocumentHandler getFormatterListener()
{
return m_documentHandler;
}
/**
* Set the FormatterListener (the SAX DocumentHandler).
*/
public void setFormatterListener(DocumentHandler flistener)
{
m_documentHandler = flistener;
}
/**
* Get the current SAX DocumentHandler (the same object as the FormatterListener), or null if none has been set.
*/
public DocumentHandler getDocumentHandler()
{
return m_documentHandler;
}
/**
* Set the current SAX DocumentHandler (the same
* object as the FormatterListener).
*/
public void setDocumentHandler(DocumentHandler listener)
{
if (listener instanceof ParserAdapter)
m_transformerImpl.setContentHandler(((ParserAdapter)listener).getContentHandler());
else if (listener instanceof XSLTEngineImpl)
m_transformerImpl.setContentHandler(((XSLTEngineImpl)listener).getTransformer().getContentHandler());
else if (listener instanceof XMLSerializer)
{
try{
m_transformerImpl.setContentHandler(((XMLSerializer)listener).asContentHandler());
}
catch (IOException ioe)
{}
}
m_documentHandler = listener;
}
/**
* Add a trace listener for the purposes of debugging and diagnosis.
* @param tl Trace listener to be added.
*/
public void addTraceListener(TraceListener tl)
throws TooManyListenersException
{
if (m_transformerImpl != null)
m_transformerImpl.getTraceManager().addTraceListener(tl);
}
/**
* If set to true (the default), pattern conflict warnings are not printed to the diagnostics stream.
* @param b true if conflict warnings should be suppressed.
*/
public void setQuietConflictWarnings(boolean b)
{
if (m_transformerImpl != null)
m_transformerImpl.setQuietConflictWarnings(b);
}
/**
* Remove a trace listener.
* @param tl Trace listener to be removed.
*/
public void removeTraceListener(TraceListener tl)
{
if (m_transformerImpl != null)
m_transformerImpl.getTraceManager().removeTraceListener(tl);
}
/**
* Set the problem listener property.
* The XSL class can have a single listener to be informed
* of errors and warnings. The problem listener normally controls whether an exception
* is thrown or not (or the problem listeners can throw its own RuntimeException).
* @param l A ProblemListener interface.
*/
public void setProblemListener(ProblemListener l)
{
if (l instanceof ProblemListenerDefault)
m_problemListener = (ProblemListenerDefault)l;
else
m_problemListener = new ProblemListenerDefault(l);
if (m_transformerImpl != null)
m_transformerImpl.setErrorListener(m_problemListener);
m_tfactory.setErrorListener(m_problemListener);
}
/**
* Get the problem listener property.
* The XSL class can have a single listener to be informed
* of errors and warnings. The problem listener normally controls whether an exception
* is thrown or not (or the problem listener can throw its own RuntimeException).
* @return A ProblemListener interface.
*/
public ProblemListener getProblemListener()
{
if (m_problemListener.getProblemListener() != null)
return m_problemListener.getProblemListener();
else
return m_problemListener;
}
public TransformerImpl getTransformer()
{
return m_transformerImpl;
//return (StylesheetProcessor)m_processor;
}
public TransformerFactoryImpl getTransformerFactory()
{
return (TransformerFactoryImpl)m_tfactory;
}
} // end XSLTEngineImpl class