/* * Copyright (c) 1998-2011 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 Emil Ong */ package com.caucho.xml.stream; import com.caucho.util.L10N; import com.caucho.xml.QDocument; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import static javax.xml.XMLConstants.*; import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.dom.DOMResult; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Logger; public class DOMResultXMLStreamWriterImpl implements XMLStreamWriter { private static final Logger log = Logger.getLogger(DOMResultXMLStreamWriterImpl.class.getName()); private static final L10N L = new L10N(DOMResultXMLStreamWriterImpl.class); private DOMResult _result; private Document _document; private Node _current; private boolean _currentIsEmpty = false; private boolean _repair = false; private NamespaceWriterContext _tracker; public DOMResultXMLStreamWriterImpl(DOMResult result) throws XMLStreamException { this(result, false); } public DOMResultXMLStreamWriterImpl(DOMResult result, boolean repair) throws XMLStreamException { _result = result; _repair = repair; _tracker = new NamespaceWriterContext(repair); _current = result.getNode(); if (_current == null) { _current = _document = new QDocument(); result.setNode(_document); } else { if (_current.getNodeType() == Node.DOCUMENT_NODE) _document = (Document) _current; else _document = _current.getOwnerDocument(); } } public void close() throws XMLStreamException { writeEndDocument(); } public void flush() throws XMLStreamException { } public NamespaceContext getNamespaceContext() { return _tracker; } public String getPrefix(String uri) throws XMLStreamException { return _tracker.getPrefix(uri); } public Object getProperty(String name) throws IllegalArgumentException { throw new PropertyNotSupportedException(name); } public void setDefaultNamespace(String uri) throws XMLStreamException { _tracker.declare(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 { try { ((Element) _current).setAttribute(localName, value); } catch (ClassCastException e) { throw new XMLStreamException(e); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { if (_repair) { String prefix = _tracker.declare(namespaceURI); if (prefix == null) ((Element) _current).setAttributeNS(namespaceURI, localName, value); else { String qname = prefix + ':' + localName; ((Element) _current).setAttributeNS(namespaceURI, qname, value); } } else { String prefix = _tracker.getPrefix(namespaceURI); if (prefix == null) throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI)); String qname = prefix + ':' + localName; ((Element) _current).setAttributeNS(namespaceURI, qname, value); } } public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException { try { if (_repair && _tracker.getPrefix(namespaceURI) == null) _tracker.declare(prefix, namespaceURI, true); else _tracker.declare(prefix, namespaceURI); String qname = prefix + ':' + localName; ((Element) _current).setAttributeNS(namespaceURI, qname, value); } catch (ClassCastException e) { throw new XMLStreamException(e); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeCData(String data) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { _current.appendChild(_document.createCDATASection(data)); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { writeCharacters(new String(text, start, len)); } public void writeCharacters(String text) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { _current.appendChild(_document.createTextNode(text)); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeComment(String data) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { _current.appendChild(_document.createComment(data)); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { _tracker.declare("", namespaceURI, true); } public void writeDTD(String dtd) throws XMLStreamException { throw new UnsupportedOperationException(); } public void writeEmptyElement(String localName) throws XMLStreamException { if (_currentIsEmpty) popContext(); try { Node parent = _current; _current = _document.createElement(localName); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = true; } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { if (_currentIsEmpty) popContext(); try { String qname = localName; if (_repair) { String prefix = _tracker.declare(namespaceURI); if (prefix != null) qname = prefix + ':' + localName; } else { String prefix = _tracker.getPrefix(namespaceURI); if (prefix == null) throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI)); qname = prefix + ':' + localName; } Node parent = _current; _current = _document.createElementNS(namespaceURI, qname); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = true; } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { if (_currentIsEmpty) popContext(); try { if (_repair && _tracker.getPrefix(namespaceURI) == null) _tracker.declare(prefix, namespaceURI, true); Node parent = _current; String qname = prefix + ':' + localName; _current = _document.createElementNS(namespaceURI, qname); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = true; } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeEndDocument() throws XMLStreamException { } public void writeEndElement() throws XMLStreamException { try { popContext(); if (_currentIsEmpty) popContext(); _currentIsEmpty = false; } catch (ClassCastException e) { throw new XMLStreamException(e); } } public void writeEntityRef(String name) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { _current.appendChild(_document.createEntityReference(name)); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix)) writeDefaultNamespace(namespaceURI); else { _tracker.declare(prefix, namespaceURI, true); if (! (_current instanceof Element)) throw new XMLStreamException(L.l("Cannot write namespace without an element")); String qname = XMLNS_ATTRIBUTE + ':' + prefix; ((Element) _current).setAttributeNS(XML_NS_URI, qname, namespaceURI); } } public void writeProcessingInstruction(String target) throws XMLStreamException { writeProcessingInstruction(target, ""); } public void writeProcessingInstruction(String target, String data) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { _current.appendChild(_document.createProcessingInstruction(target, data)); } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeStartDocument() throws XMLStreamException { writeStartDocument("1.0"); } public void writeStartDocument(String version) throws XMLStreamException { writeStartDocument(version, "utf-8"); } public void writeStartDocument(String version, String encoding) throws XMLStreamException { try { _document.setXmlVersion(version); // XXX encoding } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeStartElement(String localName) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { Node parent = _current; _current = _document.createElement(localName); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = false; } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { String qname = localName; if (_repair) { String prefix = _tracker.declare(namespaceURI); if (prefix != null) qname = prefix + ':' + localName; } else { String prefix = _tracker.getPrefix(namespaceURI); if (prefix == null) throw new XMLStreamException(L.l("No prefix defined for namespace {0}", namespaceURI)); qname = prefix + ':' + localName; } Node parent = _current; _current = _document.createElementNS(namespaceURI, qname); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = false; } catch (DOMException e) { throw new XMLStreamException(e); } } public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { if (_currentIsEmpty) { popContext(); _currentIsEmpty = false; } try { if (_repair && _tracker.getPrefix(namespaceURI) == null) _tracker.declare(prefix, namespaceURI, true); Node parent = _current; String qname = prefix + ':' + localName; _current = _document.createElementNS(namespaceURI, qname); parent.appendChild(_current); if (! (parent instanceof Document)) pushContext(); _currentIsEmpty = false; } catch (DOMException e) { throw new XMLStreamException(e); } } ////////////////////////////////////////////////////////////////////////// private boolean _flushed = true; private void pushContext() throws DOMException { _tracker.push(); _flushed = false; } private void popContext() throws DOMException, XMLStreamException { _tracker.pop(); _current = _current.getParentNode(); } }