com.caucho.xml.stream.XMLStreamWriterImpl Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Adam Megacz
*/
package com.caucho.xml.stream;
import com.caucho.vfs.WriteStream;
import com.caucho.vfs.Vfs;
import com.caucho.util.L10N;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.logging.Logger;
public class XMLStreamWriterImpl implements XMLStreamWriter {
private static final L10N L = new L10N(XMLStreamWriterImpl.class);
private static final Logger log
= Logger.getLogger(XMLStreamReaderImpl.class.getName());
private WriteStream _out;
private NamespaceWriterContext _tracker;
private QName _pendingTagName = null;
private boolean _shortTag = false;
private boolean _repair = false;
private ArrayList _pendingAttributeNames = new ArrayList();
private ArrayList _pendingAttributeValues = new ArrayList();
private int _indent = -1;
private int _currentIndent;
private boolean _flushed = true;
public XMLStreamWriterImpl(WriteStream ws)
{
this(ws, false);
}
public XMLStreamWriterImpl(WriteStream ws, boolean repair)
{
_out = ws;
_repair = repair;
_tracker = new NamespaceWriterContext(repair);
}
public XMLStreamWriterImpl(Writer w, boolean repair)
{
this(Vfs.openWrite(w), repair);
}
public XMLStreamWriterImpl(OutputStream os, boolean repair)
{
this(Vfs.openWrite(os), repair);
}
public void setIndent(int indent)
{
_indent = indent;
}
public void setRepair(boolean repair)
{
_repair = repair;
_tracker.setRepair(repair);
}
public void close() throws XMLStreamException
{
flushPending();
flush();
// DO NOT close _out!
// This will cause XFire/CXF and possibly others to blow up.
}
public void flush() throws XMLStreamException
{
try {
_out.flush();
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public NamespaceContext getNamespaceContext()
{
return _tracker;
}
public String getPrefix(String uri)
throws XMLStreamException
{
return _tracker.getPrefix(uri);
}
public Object getProperty(String name)
throws IllegalArgumentException
{
if (XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name))
return Boolean.valueOf(_repair);
throw new PropertyNotSupportedException(name);
}
public void setDefaultNamespace(String uri)
throws XMLStreamException
{
_tracker.declare(XMLConstants.DEFAULT_NS_PREFIX, uri, _repair);
}
public void setNamespaceContext(NamespaceContext context)
throws XMLStreamException
{
String message = "please do not set the NamespaceContext";
throw new UnsupportedOperationException(message);
}
public void setPrefix(String prefix, String uri)
throws XMLStreamException
{
_tracker.declare(prefix, uri);
}
public void writeAttribute(String localName, String value)
throws XMLStreamException
{
_pendingAttributeNames.add(new QName(localName));
_pendingAttributeValues.add(value);
}
public void writeAttribute(String namespaceURI, String localName,
String value)
throws XMLStreamException
{
if (_repair) {
String prefix = _tracker.declare(namespaceURI);
if (prefix == null)
_pendingAttributeNames.add(new QName(namespaceURI, localName));
else
_pendingAttributeNames.add(new QName(namespaceURI, localName, prefix));
}
else {
String prefix = _tracker.getPrefix(namespaceURI);
if (prefix == null)
throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI));
_pendingAttributeNames.add(new QName(namespaceURI, localName, prefix));
}
_pendingAttributeValues.add(value);
}
public void writeAttribute(String prefix, String namespaceURI,
String localName, String value)
throws XMLStreamException
{
if (prefix == null || "".equals(prefix))
throw new XMLStreamException(L.l("Attribute namespace prefixes cannot be null or empty"));
if (_repair && _tracker.getPrefix(namespaceURI) == null)
_tracker.declare(prefix, namespaceURI, true);
else
_tracker.declare(prefix, namespaceURI);
_pendingAttributeNames.add(new QName(namespaceURI, localName, prefix));
_pendingAttributeValues.add(value);
}
public void writeCData(String data)
throws XMLStreamException
{
flushPending();
try {
_out.print("");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeCharacters(char[] text, int start, int len)
throws XMLStreamException
{
flushPending();
try {
Escapifier.escape(text, start, len, _out);
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeCharacters(String text)
throws XMLStreamException
{
flushPending();
try {
Escapifier.escape(text, _out);
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeComment(String data)
throws XMLStreamException
{
flushPending();
try {
_out.print("");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeDefaultNamespace(String namespaceURI)
throws XMLStreamException
{
_tracker.declare("", namespaceURI, true);
}
public void writeDTD(String dtd)
throws XMLStreamException
{
flushPending();
try {
_out.print(dtd);
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeElement(String localName, String contents)
throws XMLStreamException
{
writeStartElement(localName);
if (contents != null)
writeCharacters(contents);
writeEndElement();
}
public void writeEmptyElement(String localName)
throws XMLStreamException
{
flushPending();
try {
QName qname = new QName(localName);
pushContext(qname);
_pendingTagName = qname;
_shortTag = true;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeEmptyElement(String namespaceURI, String localName)
throws XMLStreamException
{
flushPending();
try {
QName qname = null;
if (_repair) {
// NOTE: We have to push before we declare because declare will
// declare the namespace in the parent context if we don't
flushContext();
_tracker.push();
String prefix = _tracker.declare(namespaceURI);
if (prefix == null)
qname = new QName(namespaceURI, localName);
else
qname = new QName(namespaceURI, localName, prefix);
_tracker.setElementName(qname);
_flushed = false;
}
else {
String prefix = _tracker.getPrefix(namespaceURI);
if (prefix == null)
throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI));
qname = new QName(namespaceURI, localName, prefix);
pushContext(qname);
}
_pendingTagName = qname;
_shortTag = true;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeEmptyElement(String prefix, String localName,
String namespaceURI)
throws XMLStreamException
{
flushPending();
try {
QName qname = new QName(namespaceURI, localName, prefix);
if (_repair && _tracker.getPrefix(namespaceURI) == null) {
// NOTE: We have to push before we declare because declare will
// declare the namespace in the parent context if we don't
flushContext();
_tracker.push();
_tracker.declare(prefix, namespaceURI, true);
_tracker.setElementName(qname);
_flushed = false;
}
else
pushContext(qname);
_pendingTagName = qname;
_shortTag = true;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeEndDocument()
throws XMLStreamException
{
}
public void writeEndElement()
throws XMLStreamException
{
writeEndElement(null, null);
}
public void writeEndElement(String localName)
throws XMLStreamException
{
writeEndElement(null, localName);
}
public void writeEndElement(String namespaceURI, String localName)
throws XMLStreamException
{
flushPending();
try {
QName name = popContext();
if ((localName != null && !localName.equals(name.getLocalPart()))
|| (namespaceURI != null && !namespaceURI.equals(name.getNamespaceURI())))
throw new XMLStreamException(L.l("unbalanced close, expecting `{0}' not `{1}'",
name, new QName(namespaceURI, localName)));
_out.print("");
_out.print(printQName(name));
_out.print(">");
if (_indent >= 0) {
_out.println();
_currentIndent -= _indent;
}
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
private static String printQName(QName name) {
if (name.getPrefix() == null || name.getPrefix().equals(""))
return name.getLocalPart();
return name.getPrefix() + ":" + name.getLocalPart();
}
public void writeEntityRef(String name)
throws XMLStreamException
{
flushPending();
try {
_out.print("&");
_out.print(name);
_out.print(";");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeNamespace(String prefix, String namespaceURI)
throws XMLStreamException
{
if (_pendingTagName == null)
throw new XMLStreamException("Namespace written before element");
if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix))
writeDefaultNamespace(namespaceURI);
else
_tracker.declare(prefix, namespaceURI, true);
}
public void writeProcessingInstruction(String target)
throws XMLStreamException
{
flushPending();
try {
_out.print("");
_out.print(target);
_out.print("?>");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeProcessingInstruction(String target, String data)
throws XMLStreamException
{
flushPending();
try {
_out.print("");
_out.print(target);
_out.print(" ");
_out.print(data);
_out.print("?>");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeStartDocument()
throws XMLStreamException
{
writeStartDocument("1.0");
}
public void writeStartDocument(String version)
throws XMLStreamException
{
writeStartDocument("utf-8", version);
}
public void writeStartDocument(String encoding, String version)
throws XMLStreamException
{
try {
_out.print("");
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeStartElement(String localName)
throws XMLStreamException
{
flushPending();
try {
QName qname = new QName(localName);
pushContext(qname);
_pendingTagName = qname;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeStartElement(String namespaceURI, String localName)
throws XMLStreamException
{
flushPending();
try {
QName qname = null;
if (_repair) {
// NOTE: We have to push before we declare because declare will
// declare the namespace in the parent context if we don't
flushContext();
_tracker.push();
String prefix = _tracker.declare(namespaceURI);
if (prefix == null)
qname = new QName(namespaceURI, localName);
else
qname = new QName(namespaceURI, localName, prefix);
_tracker.setElementName(qname);
_flushed = false;
}
else {
String prefix = _tracker.getPrefix(namespaceURI);
if (prefix == null)
throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI));
qname = new QName(namespaceURI, localName, prefix);
pushContext(qname);
}
_pendingTagName = qname;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
public void writeStartElement(String prefix, String localName,
String namespaceURI)
throws XMLStreamException
{
flushPending();
try {
QName qname = new QName(namespaceURI, localName, prefix);
if (_repair && _tracker.getPrefix(namespaceURI) == null) {
// NOTE: We have to push before we declare because declare will
// declare the namespace in the parent context if we don't
flushContext();
_tracker.push();
_tracker.declare(prefix, namespaceURI, true);
_tracker.setElementName(qname);
_flushed = false;
}
else
pushContext(qname);
_pendingTagName = qname;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
/////////////////////////////////////////////////////////////////////////
private void pushContext(QName elementName)
throws IOException
{
flushContext();
_tracker.push();
_tracker.setElementName(elementName);
_flushed = false;
}
private QName popContext()
throws IOException, XMLStreamException
{
flushContext();
QName name = _tracker.getElementName();
_tracker.pop();
return name;
}
private void flushContext()
throws IOException
{
if (_flushed)
return;
_tracker.emitDeclarations(_out);
_flushed = true;
}
private void flushPending()
throws XMLStreamException
{
try {
if (_pendingTagName == null)
return;
_out.print("<");
_out.print(printQName(_pendingTagName));
for(int i = 0; i < _pendingAttributeNames.size(); i++) {
_out.print(" ");
_out.print(printQName(_pendingAttributeNames.get(i)));
_out.print("=\"");
Escapifier.escape(_pendingAttributeValues.get(i), _out);
_out.print('"');
}
flushContext();
if (_shortTag) {
_out.print("/>");
popContext();
} else {
_out.print(">");
if (_indent > -1)
_currentIndent += _indent;
}
_pendingTagName = null;
_pendingAttributeNames.clear();
_pendingAttributeValues.clear();
_shortTag = false;
}
catch (IOException e) {
throw new XMLStreamException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy