/* * Copyright (C) 2011 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.rendering; import java.io.OutputStream; import java.nio.charset.Charset; import com.google.common.base.Preconditions; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; import org.novelang.common.Nodepath; import org.novelang.common.metadata.DocumentMetadata; import org.novelang.outfit.DefaultCharset; import org.novelang.outfit.xml.XmlNamespaces; import org.novelang.parser.NodeKindTools; /** * @author Laurent Caillette */ public class XmlWriter implements FragmentWriter { private ContentHandler contentHandler ; private final String namespaceUri ; private final String nameQualifier ; private final Charset charset ; private final RenditionMimeType mimeType ; public XmlWriter( final RenditionMimeType mimeType ) { this( XmlNamespaces.TREE_NAMESPACE_URI, XmlNamespaces.TREE_NAME_QUALIFIER, DefaultCharset.RENDERING, mimeType ) ; } public XmlWriter( final String namespaceUri, final String nameQualifier, final Charset charset, final RenditionMimeType mimeType ) { this.namespaceUri = Preconditions.checkNotNull( namespaceUri ) ; this.nameQualifier = Preconditions.checkNotNull( nameQualifier ) ; this.charset = Preconditions.checkNotNull( charset ) ; this.mimeType = mimeType; } public XmlWriter() { this( RenditionMimeType.XML ) ; } @Override public void startWriting( final OutputStream outputStream, final DocumentMetadata documentMetadata ) throws Exception { contentHandler = createContentHandler( outputStream, documentMetadata, charset ) ; contentHandler.startDocument() ; } @Override public void finishWriting() throws Exception { contentHandler.endDocument() ; if( contentHandler instanceof XMLWriter ) { ( ( XMLWriter ) contentHandler ).flush() ; } } @Override public void start( final Nodepath kinship, final boolean wholeDocument ) throws Exception { start( NodeKindTools.tokenNameAsXmlElementName( kinship.getCurrent().name() ), wholeDocument ) ; } public void start( final String elementName ) throws Exception { start( elementName, false ) ; } public void start( final String elementName, final boolean wholeDocument ) throws Exception { final Attributes attributes ; if( wholeDocument ) { // Declare the namespace. final AttributesImpl mutableAttributes = new AttributesImpl() ; mutableAttributes.addAttribute( namespaceUri, nameQualifier, "xmlns:" + nameQualifier, "CDATA", namespaceUri ) ; attributes = mutableAttributes ; } else { attributes = EMPTY_ATTRIBUTES ; } contentHandler.startElement( namespaceUri, elementName, nameQualifier + ":" + elementName, attributes ) ; } @Override public void end( final Nodepath kinship ) throws Exception { end( NodeKindTools.tokenNameAsXmlElementName( kinship.getCurrent().name() ) ) ; } public void end( final String elementName ) throws Exception { contentHandler.endElement( namespaceUri, elementName, nameQualifier + ":" + elementName ) ; } public void write( final String word ) throws Exception { write( null, word ) ; } @Override public void write( final Nodepath kinship, final String word ) throws Exception { contentHandler.characters( word.toCharArray(), 0, word.length() ) ; } @Override public void writeLiteral( final Nodepath kinship, final String word ) throws Exception { ( ( LexicalHandler ) contentHandler ).startCDATA() ; contentHandler.characters( word.toCharArray(), 0, word.length() ) ; ( ( LexicalHandler ) contentHandler ).endCDATA() ; } @Override public RenditionMimeType getMimeType() { return mimeType ; } protected ContentHandler createContentHandler( final OutputStream outputStream, final DocumentMetadata documentMetadata, final Charset charset ) throws Exception { final OutputFormat outputFormat = new OutputFormat( " ", true, charset.name() ) ; outputFormat.setExpandEmptyElements( false ) ; outputFormat.setXHTML( true ) ; return new XMLWriter( // That's another class, not an instance of the current one. outputStream, outputFormat ) ; } private static final Attributes EMPTY_ATTRIBUTES = new AttributesImpl() ; }