mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			806 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			806 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* TransformerImpl.java --
 | |
|    Copyright (C) 2004,2005,2006 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| package gnu.xml.transform;
 | |
| 
 | |
| import gnu.java.lang.CPStringBuilder;
 | |
| 
 | |
| import java.io.BufferedOutputStream;
 | |
| import java.io.FileOutputStream;
 | |
| import java.io.IOException;
 | |
| import java.io.OutputStream;
 | |
| import java.io.UnsupportedEncodingException;
 | |
| import java.io.Writer;
 | |
| import java.net.MalformedURLException;
 | |
| import java.net.UnknownServiceException;
 | |
| import java.net.URL;
 | |
| import java.net.URLConnection;
 | |
| import java.util.Collection;
 | |
| import java.util.Iterator;
 | |
| import java.util.LinkedList;
 | |
| import java.util.List;
 | |
| import java.util.Properties;
 | |
| import java.util.StringTokenizer;
 | |
| import javax.xml.namespace.QName;
 | |
| import javax.xml.transform.ErrorListener;
 | |
| import javax.xml.transform.OutputKeys;
 | |
| import javax.xml.transform.Result;
 | |
| import javax.xml.transform.Source;
 | |
| import javax.xml.transform.Transformer;
 | |
| import javax.xml.transform.TransformerConfigurationException;
 | |
| import javax.xml.transform.TransformerException;
 | |
| import javax.xml.transform.URIResolver;
 | |
| import javax.xml.transform.dom.DOMSource;
 | |
| import javax.xml.transform.dom.DOMResult;
 | |
| import javax.xml.transform.sax.SAXResult;
 | |
| import javax.xml.transform.stream.StreamResult;
 | |
| import org.w3c.dom.Document;
 | |
| import org.w3c.dom.DocumentType;
 | |
| import org.w3c.dom.DOMImplementation;
 | |
| import org.w3c.dom.Node;
 | |
| import org.w3c.dom.Text;
 | |
| import org.xml.sax.ContentHandler;
 | |
| import org.xml.sax.SAXException;
 | |
| import org.xml.sax.ext.LexicalHandler;
 | |
| import gnu.xml.dom.DomDoctype;
 | |
| import gnu.xml.dom.DomDocument;
 | |
| import gnu.xml.dom.ls.WriterOutputStream;
 | |
| 
 | |
| /**
 | |
|  * The transformation process for a given stylesheet.
 | |
|  *
 | |
|  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
 | |
|  */
 | |
| class TransformerImpl
 | |
|   extends Transformer
 | |
| {
 | |
| 
 | |
|   final TransformerFactoryImpl factory;
 | |
|   final Stylesheet stylesheet;
 | |
|   URIResolver uriResolver;
 | |
|   ErrorListener errorListener;
 | |
|   Properties outputProperties;
 | |
| 
 | |
|   TransformerImpl(TransformerFactoryImpl factory,
 | |
|                   Stylesheet stylesheet,
 | |
|                   Properties outputProperties)
 | |
|     throws TransformerConfigurationException
 | |
|   {
 | |
|     this.factory = factory;
 | |
|     uriResolver = factory.userResolver;
 | |
|     errorListener = factory.userListener;
 | |
|     this.stylesheet = stylesheet;
 | |
|     this.outputProperties = outputProperties;
 | |
|     if (stylesheet != null)
 | |
|       {
 | |
|         // Set up parameter context for this transformer
 | |
|         stylesheet.bindings.push(Bindings.PARAM);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void transform(Source xmlSource, Result outputTarget)
 | |
|     throws TransformerException
 | |
|   {
 | |
|     // Get the source tree
 | |
|     DOMSource source;
 | |
|     synchronized (factory.resolver)
 | |
|       {
 | |
|         factory.resolver.setUserResolver(uriResolver);
 | |
|         factory.resolver.setUserListener(errorListener);
 | |
|         source = factory.resolver.resolveDOM(xmlSource, null, null);
 | |
|       }
 | |
|     Node context = source.getNode();
 | |
|     Document doc = (context instanceof Document) ? (Document) context :
 | |
|       context.getOwnerDocument();
 | |
|     if (doc instanceof DomDocument)
 | |
|       {
 | |
|         // Suppress mutation events
 | |
|         ((DomDocument) doc).setBuilding(true);
 | |
|       }
 | |
|     // Get the result tree
 | |
|     Node parent = null, nextSibling = null;
 | |
|     if (outputTarget instanceof DOMResult)
 | |
|       {
 | |
|         DOMResult dr = (DOMResult) outputTarget;
 | |
|         parent = dr.getNode();
 | |
|         nextSibling = dr.getNextSibling();
 | |
| 
 | |
|         Document rdoc = (parent instanceof Document) ? (Document) parent :
 | |
|           parent.getOwnerDocument();
 | |
|         if (rdoc instanceof DomDocument)
 | |
|           {
 | |
|             // Suppress mutation events and allow multiple root elements
 | |
|             DomDocument drdoc = (DomDocument) rdoc;
 | |
|             drdoc.setBuilding(true);
 | |
|             drdoc.setCheckWellformedness(false);
 | |
|           }
 | |
|       }
 | |
|     boolean created = false;
 | |
|     // Transformation
 | |
|     if (stylesheet != null)
 | |
|       {
 | |
|         if (parent == null)
 | |
|           {
 | |
|             // Create a new document to hold the result
 | |
|             DomDocument resultDoc = new DomDocument();
 | |
|             resultDoc.setBuilding(true);
 | |
|             resultDoc.setCheckWellformedness(false);
 | |
|             parent = resultDoc;
 | |
|             created = true;
 | |
|           }
 | |
|         // Make a copy of the source node, and strip it
 | |
|         context = context.cloneNode(true);
 | |
|         strip(stylesheet, context);
 | |
|         // XSLT transformation
 | |
|         try
 | |
|           {
 | |
|             // Set output properties in the underlying stylesheet
 | |
|             ((TransformerOutputProperties) outputProperties).apply();
 | |
|             stylesheet.initTopLevelVariables(context);
 | |
|             TemplateNode t = stylesheet.getTemplate(null, context, false);
 | |
|             if (t != null)
 | |
|               {
 | |
|                 stylesheet.current = context;
 | |
|                 t.apply(stylesheet, null, context, 1, 1, parent, nextSibling);
 | |
|               }
 | |
|           }
 | |
|         catch (TransformerException e)
 | |
|           {
 | |
|             // Done transforming, reset document
 | |
|             if (doc instanceof DomDocument)
 | |
|               ((DomDocument) doc).setBuilding(false);
 | |
|             throw e;
 | |
|           }
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         // Identity transform
 | |
|         Node clone = context.cloneNode(true);
 | |
|         if (context.getNodeType() != Node.DOCUMENT_NODE)
 | |
|           {
 | |
|             Document resultDoc;
 | |
|             if (parent == null)
 | |
|               {
 | |
|                 // Create a new document to hold the result
 | |
|                 DomDocument rd = new DomDocument();
 | |
|                 rd.setBuilding(true);
 | |
|                 rd.setCheckWellformedness(false);
 | |
|                 parent = resultDoc = rd;
 | |
|                 created = true;
 | |
|               }
 | |
|             else
 | |
|               {
 | |
|                 resultDoc = (parent instanceof Document) ?
 | |
|                   (Document) parent :
 | |
|                   parent.getOwnerDocument();
 | |
|               }
 | |
|             Document sourceDoc = context.getOwnerDocument();
 | |
|             if (sourceDoc != resultDoc)
 | |
|               clone = resultDoc.adoptNode(clone);
 | |
|             if (nextSibling != null)
 | |
|               parent.insertBefore(clone, nextSibling);
 | |
|             else
 | |
|               parent.appendChild(clone);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             // Cannot append document to another tree
 | |
|             parent = clone;
 | |
|             created = true;
 | |
|           }
 | |
|       }
 | |
|     String method = outputProperties.getProperty(OutputKeys.METHOD);
 | |
|     int outputMethod = "html".equals(method) ? Stylesheet.OUTPUT_HTML :
 | |
|       "text".equals(method) ? Stylesheet.OUTPUT_TEXT :
 | |
|       Stylesheet.OUTPUT_XML;
 | |
|     String encoding = outputProperties.getProperty(OutputKeys.ENCODING);
 | |
|     String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC);
 | |
|     String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM);
 | |
|     String version = outputProperties.getProperty(OutputKeys.VERSION);
 | |
|     boolean omitXmlDeclaration =
 | |
|       "yes".equals(outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION));
 | |
|     boolean standalone =
 | |
|       "yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE));
 | |
|     String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
 | |
|     String cdataSectionElements =
 | |
|       outputProperties.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
 | |
|     boolean indent =
 | |
|       "yes".equals(outputProperties.getProperty(OutputKeys.INDENT));
 | |
|     if (created && parent instanceof DomDocument)
 | |
|       {
 | |
|         // Discover document element
 | |
|         DomDocument resultDoc = (DomDocument) parent;
 | |
|         Node root = resultDoc.getDocumentElement();
 | |
|         // Add doctype if specified
 | |
|         if (publicId != null || systemId != null)
 | |
|           {
 | |
|             if (root != null)
 | |
|               {
 | |
|                 // We must know the name of the root element to
 | |
|                 // create the document type
 | |
|                 DocumentType doctype = new DomDoctype(resultDoc,
 | |
|                                                       root.getNodeName(),
 | |
|                                                       publicId,
 | |
|                                                       systemId);
 | |
|                 resultDoc.insertBefore(doctype, root);
 | |
|               }
 | |
|           }
 | |
|         resultDoc.setBuilding(false);
 | |
|         resultDoc.setCheckWellformedness(true);
 | |
|       }
 | |
|     else if (publicId != null || systemId != null)
 | |
|       {
 | |
|         switch (parent.getNodeType())
 | |
|           {
 | |
|           case Node.DOCUMENT_NODE:
 | |
|           case Node.DOCUMENT_FRAGMENT_NODE:
 | |
|             Document resultDoc = (parent instanceof Document) ?
 | |
|               (Document) parent :
 | |
|               parent.getOwnerDocument();
 | |
|             DOMImplementation impl = resultDoc.getImplementation();
 | |
|             Node root = resultDoc.getDocumentElement();
 | |
|             if (root != null)
 | |
|               {
 | |
|                 DocumentType doctype =
 | |
|                   impl.createDocumentType(root.getNodeName(),
 | |
|                                           publicId,
 | |
|                                           systemId);
 | |
|                 resultDoc.insertBefore(doctype, root);
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|     if (version != null)
 | |
|       parent.setUserData("version", version, stylesheet);
 | |
|     if (omitXmlDeclaration)
 | |
|       parent.setUserData("omit-xml-declaration", "yes", stylesheet);
 | |
|     if (standalone)
 | |
|       parent.setUserData("standalone", "yes", stylesheet);
 | |
|     if (mediaType != null)
 | |
|       parent.setUserData("media-type", mediaType, stylesheet);
 | |
|     if (cdataSectionElements != null)
 | |
|       {
 | |
|         List list = new LinkedList();
 | |
|         StringTokenizer st = new StringTokenizer(cdataSectionElements);
 | |
|         while (st.hasMoreTokens())
 | |
|           {
 | |
|             String name = st.nextToken();
 | |
|             String localName = name;
 | |
|             String uri = null;
 | |
|             String prefix = null;
 | |
|             int ci = name.indexOf(':');
 | |
|             if (ci != -1)
 | |
|               {
 | |
|                 // Use namespaces defined on xsl:output node to resolve
 | |
|                 // namespaces for QName
 | |
|                 prefix = name.substring(0, ci);
 | |
|                 localName = name.substring(ci + 1);
 | |
|                 uri = stylesheet.output.lookupNamespaceURI(prefix);
 | |
|               }
 | |
|             list.add(new QName(uri, localName, prefix));
 | |
|           }
 | |
|         if (!list.isEmpty())
 | |
|           {
 | |
|             Document resultDoc = (parent instanceof Document) ?
 | |
|               (Document) parent :
 | |
|               parent.getOwnerDocument();
 | |
|             convertCdataSectionElements(resultDoc, parent, list);
 | |
|           }
 | |
|       }
 | |
|     if (indent)
 | |
|       {
 | |
|         if (created && parent instanceof DomDocument)
 | |
|           {
 | |
|             DomDocument domDoc = (DomDocument) parent;
 | |
|             domDoc.setBuilding(true);
 | |
|             domDoc.setCheckWellformedness(false);
 | |
|           }
 | |
|         parent.normalize();
 | |
|         if (stylesheet != null)
 | |
|           strip(stylesheet, parent);
 | |
|         Document resultDoc = (parent instanceof Document) ?
 | |
|           (Document) parent :
 | |
|           parent.getOwnerDocument();
 | |
|         reindent(resultDoc, parent, 0);
 | |
|         if (created && parent instanceof DomDocument)
 | |
|           {
 | |
|             DomDocument domDoc = (DomDocument) parent;
 | |
|             domDoc.setBuilding(false);
 | |
|             domDoc.setCheckWellformedness(true);
 | |
|           }
 | |
|       }
 | |
|     // Render result to the target device
 | |
|     if (outputTarget instanceof DOMResult)
 | |
|       {
 | |
|         if (created)
 | |
|           {
 | |
|             DOMResult dr = (DOMResult) outputTarget;
 | |
|             dr.setNode(parent);
 | |
|             dr.setNextSibling(null);
 | |
|           }
 | |
|       }
 | |
|     else if (outputTarget instanceof StreamResult)
 | |
|       {
 | |
|         StreamResult sr = (StreamResult) outputTarget;
 | |
|         IOException ex = null;
 | |
|         try
 | |
|           {
 | |
|             writeStreamResult(parent, sr, outputMethod, encoding);
 | |
|           }
 | |
|         catch (UnsupportedEncodingException e)
 | |
|           {
 | |
|             try
 | |
|               {
 | |
|                 writeStreamResult(parent, sr, outputMethod, "UTF-8");
 | |
|               }
 | |
|             catch (IOException e2)
 | |
|               {
 | |
|                 ex = e2;
 | |
|               }
 | |
|           }
 | |
|         catch (IOException e)
 | |
|           {
 | |
|             ex = e;
 | |
|           }
 | |
|         if (ex != null)
 | |
|           {
 | |
|             if (errorListener != null)
 | |
|               errorListener.error(new TransformerException(ex));
 | |
|             else
 | |
|               ex.printStackTrace(System.err);
 | |
|           }
 | |
|       }
 | |
|     else if (outputTarget instanceof SAXResult)
 | |
|       {
 | |
|         SAXResult sr = (SAXResult) outputTarget;
 | |
|         try
 | |
|           {
 | |
|             ContentHandler ch = sr.getHandler();
 | |
|             LexicalHandler lh = sr.getLexicalHandler();
 | |
|             if (lh == null && ch instanceof LexicalHandler)
 | |
|               lh = (LexicalHandler) ch;
 | |
|             SAXSerializer serializer = new SAXSerializer();
 | |
|             serializer.serialize(parent, ch, lh);
 | |
|           }
 | |
|         catch (SAXException e)
 | |
|           {
 | |
|             if (errorListener != null)
 | |
|               errorListener.error(new TransformerException(e));
 | |
|             else
 | |
|               e.printStackTrace(System.err);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Strip whitespace from the source tree.
 | |
|    */
 | |
|   static boolean strip(Stylesheet stylesheet, Node node)
 | |
|     throws TransformerConfigurationException
 | |
|   {
 | |
|     short nt = node.getNodeType();
 | |
|     if (nt == Node.ENTITY_REFERENCE_NODE)
 | |
|       {
 | |
|         // Replace entity reference with its content
 | |
|         Node parent = node.getParentNode();
 | |
|         Node nextSibling = node.getNextSibling();
 | |
|         Node child = node.getFirstChild();
 | |
|         while (child != null)
 | |
|           {
 | |
|             Node next = child.getNextSibling();
 | |
|             node.removeChild(child);
 | |
|             if (nextSibling != null)
 | |
|               parent.insertBefore(child, nextSibling);
 | |
|             else
 | |
|               parent.appendChild(child);
 | |
|             child = next;
 | |
|           }
 | |
|         return true;
 | |
|       }
 | |
|     if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE)
 | |
|       {
 | |
|         // Denormalize text into whitespace and non-whitespace nodes
 | |
|         String text = node.getNodeValue();
 | |
|         String[] tokens = tokenizeWhitespace(text);
 | |
|         if (tokens.length > 1)
 | |
|           {
 | |
|             node.setNodeValue(tokens[0]);
 | |
|             Node parent = node.getParentNode();
 | |
|             Node nextSibling = node.getNextSibling();
 | |
|             Document doc = node.getOwnerDocument();
 | |
|             for (int i = 1; i < tokens.length; i++)
 | |
|               {
 | |
|                 Node newChild = (nt == Node.CDATA_SECTION_NODE) ?
 | |
|                   doc.createCDATASection(tokens[i]) :
 | |
|                   doc.createTextNode(tokens[i]);
 | |
|                 if (nextSibling != null)
 | |
|                   parent.insertBefore(newChild, nextSibling);
 | |
|                 else
 | |
|                   parent.appendChild(newChild);
 | |
|               }
 | |
|           }
 | |
|         return !stylesheet.isPreserved((Text) node, true);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         Node child = node.getFirstChild();
 | |
|         while (child != null)
 | |
|           {
 | |
|             boolean remove = strip(stylesheet, child);
 | |
|             Node next = child.getNextSibling();
 | |
|             if (remove)
 | |
|               node.removeChild(child);
 | |
|             child = next;
 | |
|           }
 | |
|       }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Tokenize the specified text into contiguous whitespace-only and
 | |
|    * non-whitespace chunks.
 | |
|    */
 | |
|   private static String[] tokenizeWhitespace(String text)
 | |
|   {
 | |
|     int len = text.length();
 | |
|     int start = 0, end = len - 1;
 | |
|     // Find index of text start
 | |
|     for (int i = 0; i < len; i++)
 | |
|       {
 | |
|         char c = text.charAt(i);
 | |
|         boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
 | |
|         if (whitespace)
 | |
|           start++;
 | |
|         else
 | |
|           break;
 | |
|       }
 | |
|     if (start == end) // all whitespace
 | |
|       return new String[] { text };
 | |
|     // Find index of text end
 | |
|     for (int i = end; i > start; i--)
 | |
|       {
 | |
|         char c = text.charAt(i);
 | |
|         boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
 | |
|         if (whitespace)
 | |
|           end--;
 | |
|         else
 | |
|           break;
 | |
|       }
 | |
|     if (start == 0 && end == len - 1) // all non-whitespace
 | |
|       return new String[] { text };
 | |
|     // whitespace, then text, then whitespace
 | |
|     String[] ret = (start > 0 && end < len - 1) ?
 | |
|       new String[3] : new String[2];
 | |
|     int i = 0;
 | |
|     if (start > 0)
 | |
|       ret[i++] = text.substring(0, start);
 | |
|     ret[i++] = text.substring(start, end + 1);
 | |
|     if (end < len - 1)
 | |
|       ret[i++] = text.substring(end + 1);
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Obtain a suitable output stream for writing the result to,
 | |
|    * and use the StreamSerializer to write the result tree to the stream.
 | |
|    */
 | |
|   void writeStreamResult(Node node, StreamResult sr, int outputMethod,
 | |
|                          String encoding)
 | |
|     throws IOException
 | |
|   {
 | |
|     OutputStream out = null;
 | |
|     boolean created = false;
 | |
|     try
 | |
|       {
 | |
|         out = sr.getOutputStream();
 | |
|         if (out == null)
 | |
|           {
 | |
|             Writer writer = sr.getWriter();
 | |
|             if (writer != null)
 | |
|               out = new WriterOutputStream(writer);
 | |
|           }
 | |
|         if (out == null)
 | |
|           {
 | |
|             String systemId = sr.getSystemId();
 | |
|             try
 | |
|               {
 | |
|                 URL url = new URL(systemId);
 | |
|                 URLConnection connection = url.openConnection();
 | |
|                 // We need to call setDoInput(false), because our
 | |
|                 // implementation of the file protocol allows writing
 | |
|                 // (unlike Sun), but it will fail with a FileNotFoundException
 | |
|                 // if we also open the connection for input and the output
 | |
|                 // file doesn't yet exist.
 | |
|                 connection.setDoInput(false);
 | |
|                 connection.setDoOutput(true);
 | |
|                 out = connection.getOutputStream();
 | |
|               }
 | |
|             catch (MalformedURLException e)
 | |
|               {
 | |
|                 out = new FileOutputStream(systemId);
 | |
|               }
 | |
|             catch (UnknownServiceException e)
 | |
|               {
 | |
|                 URL url = new URL(systemId);
 | |
|                 out = new FileOutputStream(url.getPath());
 | |
|               }
 | |
|             created = true;
 | |
|           }
 | |
|         out = new BufferedOutputStream(out);
 | |
|         StreamSerializer serializer =
 | |
|           new StreamSerializer(outputMethod, encoding, null);
 | |
|         if (stylesheet != null)
 | |
|           {
 | |
|             Collection celem = stylesheet.outputCdataSectionElements;
 | |
|             serializer.setCdataSectionElements(celem);
 | |
|           }
 | |
|         serializer.serialize(node, out);
 | |
|         out.flush();
 | |
|       }
 | |
|     finally
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             if (out != null && created)
 | |
|               out.close();
 | |
|           }
 | |
|         catch (IOException e)
 | |
|           {
 | |
|             if (errorListener != null)
 | |
|               {
 | |
|                 try
 | |
|                   {
 | |
|                     errorListener.error(new TransformerException(e));
 | |
|                   }
 | |
|                 catch (TransformerException e2)
 | |
|                   {
 | |
|                     e2.printStackTrace(System.err);
 | |
|                   }
 | |
|               }
 | |
|             else
 | |
|               e.printStackTrace(System.err);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   void copyChildren(Document dstDoc, Node src, Node dst)
 | |
|   {
 | |
|     Node srcChild = src.getFirstChild();
 | |
|     while (srcChild != null)
 | |
|       {
 | |
|         Node dstChild = dstDoc.adoptNode(srcChild);
 | |
|         dst.appendChild(dstChild);
 | |
|         srcChild = srcChild.getNextSibling();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void setParameter(String name, Object value)
 | |
|   {
 | |
|     if (stylesheet != null)
 | |
|       stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
 | |
|   }
 | |
| 
 | |
|   public Object getParameter(String name)
 | |
|   {
 | |
|     if (stylesheet != null)
 | |
|       return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   public void clearParameters()
 | |
|   {
 | |
|     if (stylesheet != null)
 | |
|       {
 | |
|         stylesheet.bindings.pop(Bindings.PARAM);
 | |
|         stylesheet.bindings.push(Bindings.PARAM);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void setURIResolver(URIResolver resolver)
 | |
|   {
 | |
|     uriResolver = resolver;
 | |
|   }
 | |
| 
 | |
|   public URIResolver getURIResolver()
 | |
|   {
 | |
|     return uriResolver;
 | |
|   }
 | |
| 
 | |
|   public void setOutputProperties(Properties oformat)
 | |
|     throws IllegalArgumentException
 | |
|   {
 | |
|     if (oformat == null)
 | |
|       outputProperties.clear();
 | |
|     else
 | |
|       outputProperties.putAll(oformat);
 | |
|   }
 | |
| 
 | |
|   public Properties getOutputProperties()
 | |
|   {
 | |
|     return (Properties) outputProperties.clone();
 | |
|   }
 | |
| 
 | |
|   public void setOutputProperty(String name, String value)
 | |
|     throws IllegalArgumentException
 | |
|   {
 | |
|     outputProperties.put(name, value);
 | |
|   }
 | |
| 
 | |
|   public String getOutputProperty(String name)
 | |
|     throws IllegalArgumentException
 | |
|   {
 | |
|     return outputProperties.getProperty(name);
 | |
|   }
 | |
| 
 | |
|   public void setErrorListener(ErrorListener listener)
 | |
|   {
 | |
|     errorListener = listener;
 | |
|   }
 | |
| 
 | |
|   public ErrorListener getErrorListener()
 | |
|   {
 | |
|     return errorListener;
 | |
|   }
 | |
| 
 | |
|   static final String INDENT_WHITESPACE = "  ";
 | |
| 
 | |
|   /*
 | |
|    * Apply indent formatting to the given tree.
 | |
|    */
 | |
|   void reindent(Document doc, Node node, int offset)
 | |
|   {
 | |
|     if (node.hasChildNodes())
 | |
|       {
 | |
|         boolean markupContent = false;
 | |
|         boolean textContent = false;
 | |
|         List children = new LinkedList();
 | |
|         Node ctx = node.getFirstChild();
 | |
|         while (ctx != null)
 | |
|           {
 | |
|             switch (ctx.getNodeType())
 | |
|               {
 | |
|               case Node.ELEMENT_NODE:
 | |
|               case Node.PROCESSING_INSTRUCTION_NODE:
 | |
|               case Node.DOCUMENT_TYPE_NODE:
 | |
|                 markupContent = true;
 | |
|                 break;
 | |
|               case Node.TEXT_NODE:
 | |
|               case Node.CDATA_SECTION_NODE:
 | |
|               case Node.ENTITY_REFERENCE_NODE:
 | |
|               case Node.COMMENT_NODE:
 | |
|                 textContent = true;
 | |
|                 break;
 | |
|               }
 | |
|             children.add(ctx);
 | |
|             ctx = ctx.getNextSibling();
 | |
|           }
 | |
|         if (markupContent)
 | |
|           {
 | |
|             if (textContent)
 | |
|               {
 | |
|                 // XXX handle mixed content differently?
 | |
|               }
 | |
|             int nodeType = node.getNodeType();
 | |
|             if (nodeType == Node.DOCUMENT_NODE)
 | |
|               {
 | |
|                 for (Iterator i = children.iterator(); i.hasNext(); )
 | |
|                   {
 | |
|                     ctx = (Node) i.next();
 | |
|                     reindent(doc, ctx, offset);
 | |
|                   }
 | |
|               }
 | |
|             else
 | |
|               {
 | |
|                 CPStringBuilder buf = new CPStringBuilder();
 | |
|                 buf.append('\n');
 | |
|                 for (int i = 0; i < offset + 1; i++)
 | |
|                   buf.append(INDENT_WHITESPACE);
 | |
|                 String ws = buf.toString();
 | |
|                 for (Iterator i = children.iterator(); i.hasNext(); )
 | |
|                   {
 | |
|                     ctx = (Node) i.next();
 | |
|                     node.insertBefore(doc.createTextNode(ws), ctx);
 | |
|                     reindent(doc, ctx, offset + 1);
 | |
|                   }
 | |
|                 buf = new CPStringBuilder();
 | |
|                 buf.append('\n');
 | |
|                 for (int i = 0; i < offset; i++)
 | |
|                   buf.append(INDENT_WHITESPACE);
 | |
|                 ws = buf.toString();
 | |
|                 node.appendChild(doc.createTextNode(ws));
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Converts the text node children of any cdata-section-elements in the
 | |
|    * tree to CDATA section nodes.
 | |
|    */
 | |
|   void convertCdataSectionElements(Document doc, Node node, List list)
 | |
|   {
 | |
|     if (node.getNodeType() == Node.ELEMENT_NODE)
 | |
|       {
 | |
|         boolean match = false;
 | |
|         for (Iterator i = list.iterator(); i.hasNext(); )
 | |
|           {
 | |
|             QName qname = (QName) i.next();
 | |
|             if (match(qname, node))
 | |
|               {
 | |
|                 match = true;
 | |
|                 break;
 | |
|               }
 | |
|           }
 | |
|         if (match)
 | |
|           {
 | |
|             Node ctx = node.getFirstChild();
 | |
|             while (ctx != null)
 | |
|               {
 | |
|                 if (ctx.getNodeType() == Node.TEXT_NODE)
 | |
|                   {
 | |
|                     Node cdata = doc.createCDATASection(ctx.getNodeValue());
 | |
|                     node.replaceChild(cdata, ctx);
 | |
|                     ctx = cdata;
 | |
|                   }
 | |
|                 ctx = ctx.getNextSibling();
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|     Node ctx = node.getFirstChild();
 | |
|     while (ctx != null)
 | |
|       {
 | |
|         if (ctx.hasChildNodes())
 | |
|           convertCdataSectionElements(doc, ctx, list);
 | |
|         ctx = ctx.getNextSibling();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   boolean match(QName qname, Node node)
 | |
|   {
 | |
|     String ln1 = qname.getLocalPart();
 | |
|     String ln2 = node.getLocalName();
 | |
|     if (ln2 == null)
 | |
|       return ln1.equals(node.getNodeName());
 | |
|     else
 | |
|       {
 | |
|         String uri1 = qname.getNamespaceURI();
 | |
|         String uri2 = node.getNamespaceURI();
 | |
|         return (uri1.equals(uri2) && ln1.equals(ln2));
 | |
|       }
 | |
|   }
 | |
| 
 | |
| }
 |