blob: 40f19143ded9e298a87f7e5004682c2ce175dd9c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.util;
import java.io.OutputStream;
import java.io.Writer;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.internal.util.XMLUtils;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Utility class that generates XML output from SAX events or DOM nodes.
*/
public class XMLSerializer {
private static final SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory
.newInstance();
private TransformerHandler mHandler;
private Transformer mTransformer;
private Result mResult;
public XMLSerializer() {
this(true);
}
public XMLSerializer(boolean isFormattedOutput) {
try {
mHandler = transformerFactory.newTransformerHandler();
mTransformer = mHandler.getTransformer();
if (isFormattedOutput) {
// set default output format
mTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
mTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
mTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
mTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
}
} catch (TransformerConfigurationException e) {
throw new UIMARuntimeException(e);
}
}
public XMLSerializer(OutputStream aOutputStream) {
this();
setOutputStream(aOutputStream);
}
public XMLSerializer(OutputStream aOutputStream, boolean isFormattedOutput) {
this(isFormattedOutput);
setOutputStream(aOutputStream);
}
public XMLSerializer(Writer aWriter) {
this();
setWriter(aWriter);
}
public XMLSerializer(Writer aWriter, boolean isFormattedOutput) {
this(isFormattedOutput);
setWriter(aWriter);
}
public void setOutputStream(OutputStream aOutputStream) {
mResult = new StreamResult(aOutputStream);
mHandler.setResult(mResult);
}
public void setWriter(Writer aWriter) {
mResult = new StreamResult(aWriter);
mHandler.setResult(mResult);
}
public ContentHandler getContentHandler() {
String xmlVer = mTransformer.getOutputProperty(OutputKeys.VERSION);
boolean xml10 = xmlVer == null || "1.0".equals(xmlVer);
return new CharacterValidatingContentHandler(!xml10, mHandler);
}
public void serialize(Node node) {
try {
mTransformer.transform(new DOMSource(node), mResult);
} catch (TransformerException e) {
throw new UIMARuntimeException(e);
}
}
public void dom2sax(Node node, ContentHandler handler) {
try {
mTransformer.transform(new DOMSource(node), new SAXResult(handler));
} catch (TransformerException e) {
throw new UIMARuntimeException(e);
}
}
public void setOutputProperty(String name, String value) {
try {
mTransformer.setOutputProperty(name, value);
} catch (IllegalArgumentException e) {
throw new UIMARuntimeException(e);
}
}
static class CharacterValidatingContentHandler implements ContentHandler {
ContentHandler mHandler;
boolean mXml11;
CharacterValidatingContentHandler(boolean xml11, ContentHandler serializerHandler) {
mHandler = serializerHandler;
mXml11 = xml11;
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
for (int i = 0; i < atts.getLength(); i++) {
String val = atts.getValue(i);
checkForInvalidXmlChars(val, mXml11);
}
mHandler.startElement(uri, localName, qName, atts);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
public void characters(char[] ch, int start, int length) throws SAXException {
checkForInvalidXmlChars(ch, start, length, mXml11);
mHandler.characters(ch, start, length);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endDocument()
*/
public void endDocument() throws SAXException {
mHandler.endDocument();
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String qName) throws SAXException {
mHandler.endElement(uri, localName, qName);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
*/
public void endPrefixMapping(String prefix) throws SAXException {
mHandler.endPrefixMapping(prefix);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
*/
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
mHandler.ignorableWhitespace(ch, start, length);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
*/
public void processingInstruction(String target, String data) throws SAXException {
mHandler.processingInstruction(target, data);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
*/
public void setDocumentLocator(Locator locator) {
mHandler.setDocumentLocator(locator);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
*/
public void skippedEntity(String name) throws SAXException {
mHandler.skippedEntity(name);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException {
mHandler.startDocument();
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
*/
public void startPrefixMapping(String prefix, String uri) throws SAXException {
mHandler.startPrefixMapping(prefix, uri);
}
private final void checkForInvalidXmlChars(String s, boolean xml11) throws SAXParseException {
final int index = XMLUtils.checkForNonXmlCharacters(s, xml11);
if (index >= 0) {
throw new SAXParseException("Trying to serialize non-XML " + (xml11 ? "1.1" : "1.0") +
" character: " + s.charAt(index)
+ ", 0x" + Integer.toHexString(s.charAt(index)), null);
}
}
private final void checkForInvalidXmlChars(char[] ch, int start, int length, boolean xml11) throws SAXParseException {
final int index = XMLUtils.checkForNonXmlCharacters(ch, start, length, xml11);
if (index >= 0) {
throw new SAXParseException("Trying to serialize non-XML " + (xml11 ? "1.1" : "1.0") +
" character: " + ch[index]
+ ", 0x" + Integer.toHexString(ch[index]), null);
}
}
}
}