001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.xml.stream;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.xml.QDocument;
034:
035: import org.w3c.dom.DOMException;
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038: import org.w3c.dom.Node;
039:
040: import static javax.xml.XMLConstants.*;
041: import javax.xml.namespace.NamespaceContext;
042: import javax.xml.stream.XMLStreamException;
043: import javax.xml.stream.XMLStreamWriter;
044: import javax.xml.transform.dom.DOMResult;
045: import java.util.ArrayList;
046: import java.util.HashMap;
047: import java.util.Iterator;
048: import java.util.List;
049: import java.util.Map;
050: import java.util.logging.Logger;
051:
052: public class DOMResultXMLStreamWriterImpl implements XMLStreamWriter {
053: private static final Logger log = Logger
054: .getLogger(DOMResultXMLStreamWriterImpl.class.getName());
055: private static final L10N L = new L10N(
056: DOMResultXMLStreamWriterImpl.class);
057:
058: private DOMResult _result;
059: private Document _document;
060: private Node _current;
061: private boolean _currentIsEmpty = false;
062: private boolean _repair = false;
063:
064: private NamespaceWriterContext _tracker;
065:
066: public DOMResultXMLStreamWriterImpl(DOMResult result)
067: throws XMLStreamException {
068: this (result, false);
069: }
070:
071: public DOMResultXMLStreamWriterImpl(DOMResult result, boolean repair)
072: throws XMLStreamException {
073: _result = result;
074: _repair = repair;
075: _tracker = new NamespaceWriterContext(repair);
076:
077: _current = result.getNode();
078:
079: if (_current == null) {
080: _current = _document = new QDocument();
081: result.setNode(_document);
082: } else {
083: if (_current.getNodeType() == Node.DOCUMENT_NODE)
084: _document = (Document) _current;
085: else
086: _document = _current.getOwnerDocument();
087: }
088: }
089:
090: public void close() throws XMLStreamException {
091: writeEndDocument();
092: }
093:
094: public void flush() throws XMLStreamException {
095: }
096:
097: public NamespaceContext getNamespaceContext() {
098: return _tracker;
099: }
100:
101: public String getPrefix(String uri) throws XMLStreamException {
102: return _tracker.getPrefix(uri);
103: }
104:
105: public Object getProperty(String name)
106: throws IllegalArgumentException {
107: throw new PropertyNotSupportedException(name);
108: }
109:
110: public void setDefaultNamespace(String uri)
111: throws XMLStreamException {
112: _tracker.declare(DEFAULT_NS_PREFIX, uri, _repair);
113: }
114:
115: public void setNamespaceContext(NamespaceContext context)
116: throws XMLStreamException {
117: String message = "please do not set the NamespaceContext";
118: throw new UnsupportedOperationException(message);
119: }
120:
121: public void setPrefix(String prefix, String uri)
122: throws XMLStreamException {
123: _tracker.declare(prefix, uri);
124: }
125:
126: public void writeAttribute(String localName, String value)
127: throws XMLStreamException {
128: try {
129: ((Element) _current).setAttribute(localName, value);
130: } catch (ClassCastException e) {
131: throw new XMLStreamException(e);
132: } catch (DOMException e) {
133: throw new XMLStreamException(e);
134: }
135: }
136:
137: public void writeAttribute(String namespaceURI, String localName,
138: String value) throws XMLStreamException {
139: if (_repair) {
140: String prefix = _tracker.declare(namespaceURI);
141:
142: if (prefix == null)
143: ((Element) _current).setAttributeNS(namespaceURI,
144: localName, value);
145: else {
146: String qname = prefix + ':' + localName;
147: ((Element) _current).setAttributeNS(namespaceURI,
148: qname, value);
149: }
150: } else {
151: String prefix = _tracker.getPrefix(namespaceURI);
152:
153: if (prefix == null)
154: throw new XMLStreamException(L.l(
155: "No prefix defined for namespace {0}",
156: namespaceURI));
157:
158: String qname = prefix + ':' + localName;
159:
160: ((Element) _current).setAttributeNS(namespaceURI, qname,
161: value);
162: }
163: }
164:
165: public void writeAttribute(String prefix, String namespaceURI,
166: String localName, String value) throws XMLStreamException {
167: try {
168: if (_repair && _tracker.getPrefix(namespaceURI) == null)
169: _tracker.declare(prefix, namespaceURI, true);
170: else
171: _tracker.declare(prefix, namespaceURI);
172:
173: String qname = prefix + ':' + localName;
174: ((Element) _current).setAttributeNS(namespaceURI, qname,
175: value);
176: } catch (ClassCastException e) {
177: throw new XMLStreamException(e);
178: } catch (DOMException e) {
179: throw new XMLStreamException(e);
180: }
181: }
182:
183: public void writeCData(String data) throws XMLStreamException {
184: if (_currentIsEmpty) {
185: popContext();
186: _currentIsEmpty = false;
187: }
188:
189: try {
190: _current.appendChild(_document.createCDATASection(data));
191: } catch (DOMException e) {
192: throw new XMLStreamException(e);
193: }
194: }
195:
196: public void writeCharacters(char[] text, int start, int len)
197: throws XMLStreamException {
198: writeCharacters(new String(text, start, len));
199: }
200:
201: public void writeCharacters(String text) throws XMLStreamException {
202: if (_currentIsEmpty) {
203: popContext();
204: _currentIsEmpty = false;
205: }
206:
207: try {
208: _current.appendChild(_document.createTextNode(text));
209: } catch (DOMException e) {
210: throw new XMLStreamException(e);
211: }
212: }
213:
214: public void writeComment(String data) throws XMLStreamException {
215: if (_currentIsEmpty) {
216: popContext();
217: _currentIsEmpty = false;
218: }
219:
220: try {
221: _current.appendChild(_document.createComment(data));
222: } catch (DOMException e) {
223: throw new XMLStreamException(e);
224: }
225: }
226:
227: public void writeDefaultNamespace(String namespaceURI)
228: throws XMLStreamException {
229: _tracker.declare("", namespaceURI, true);
230: }
231:
232: public void writeDTD(String dtd) throws XMLStreamException {
233: throw new UnsupportedOperationException();
234: }
235:
236: public void writeEmptyElement(String localName)
237: throws XMLStreamException {
238: if (_currentIsEmpty)
239: popContext();
240:
241: try {
242: Node parent = _current;
243: _current = _document.createElement(localName);
244: parent.appendChild(_current);
245:
246: if (!(parent instanceof Document))
247: pushContext();
248:
249: _currentIsEmpty = true;
250: } catch (DOMException e) {
251: throw new XMLStreamException(e);
252: }
253: }
254:
255: public void writeEmptyElement(String namespaceURI, String localName)
256: throws XMLStreamException {
257: if (_currentIsEmpty)
258: popContext();
259:
260: try {
261: String qname = localName;
262:
263: if (_repair) {
264: String prefix = _tracker.declare(namespaceURI);
265:
266: if (prefix != null)
267: qname = prefix + ':' + localName;
268: } else {
269: String prefix = _tracker.getPrefix(namespaceURI);
270:
271: if (prefix == null)
272: throw new XMLStreamException(L.l(
273: "No prefix defined for namespace {0}",
274: namespaceURI));
275:
276: qname = prefix + ':' + localName;
277: }
278:
279: Node parent = _current;
280: _current = _document.createElementNS(namespaceURI, qname);
281: parent.appendChild(_current);
282:
283: if (!(parent instanceof Document))
284: pushContext();
285:
286: _currentIsEmpty = true;
287: } catch (DOMException e) {
288: throw new XMLStreamException(e);
289: }
290: }
291:
292: public void writeEmptyElement(String prefix, String localName,
293: String namespaceURI) throws XMLStreamException {
294: if (_currentIsEmpty)
295: popContext();
296:
297: try {
298: if (_repair && _tracker.getPrefix(namespaceURI) == null)
299: _tracker.declare(prefix, namespaceURI, true);
300:
301: Node parent = _current;
302: String qname = prefix + ':' + localName;
303: _current = _document.createElementNS(namespaceURI, qname);
304: parent.appendChild(_current);
305:
306: if (!(parent instanceof Document))
307: pushContext();
308:
309: _currentIsEmpty = true;
310: } catch (DOMException e) {
311: throw new XMLStreamException(e);
312: }
313: }
314:
315: public void writeEndDocument() throws XMLStreamException {
316: }
317:
318: public void writeEndElement() throws XMLStreamException {
319: try {
320: popContext();
321:
322: if (_currentIsEmpty)
323: popContext();
324:
325: _currentIsEmpty = false;
326: } catch (ClassCastException e) {
327: throw new XMLStreamException(e);
328: }
329: }
330:
331: public void writeEntityRef(String name) throws XMLStreamException {
332: if (_currentIsEmpty) {
333: popContext();
334: _currentIsEmpty = false;
335: }
336:
337: try {
338: _current.appendChild(_document.createEntityReference(name));
339: } catch (DOMException e) {
340: throw new XMLStreamException(e);
341: }
342: }
343:
344: public void writeNamespace(String prefix, String namespaceURI)
345: throws XMLStreamException {
346: if (prefix == null || "".equals(prefix)
347: || "xmlns".equals(prefix))
348: writeDefaultNamespace(namespaceURI);
349:
350: else {
351: _tracker.declare(prefix, namespaceURI, true);
352:
353: if (!(_current instanceof Element))
354: throw new XMLStreamException(L
355: .l("Cannot write namespace without an element"));
356:
357: String qname = XMLNS_ATTRIBUTE + ':' + prefix;
358:
359: ((Element) _current).setAttributeNS(XML_NS_URI, qname,
360: namespaceURI);
361: }
362: }
363:
364: public void writeProcessingInstruction(String target)
365: throws XMLStreamException {
366: writeProcessingInstruction(target, "");
367: }
368:
369: public void writeProcessingInstruction(String target, String data)
370: throws XMLStreamException {
371: if (_currentIsEmpty) {
372: popContext();
373: _currentIsEmpty = false;
374: }
375:
376: try {
377: _current.appendChild(_document.createProcessingInstruction(
378: target, data));
379: } catch (DOMException e) {
380: throw new XMLStreamException(e);
381: }
382: }
383:
384: public void writeStartDocument() throws XMLStreamException {
385: writeStartDocument("1.0");
386: }
387:
388: public void writeStartDocument(String version)
389: throws XMLStreamException {
390: writeStartDocument(version, "utf-8");
391: }
392:
393: public void writeStartDocument(String version, String encoding)
394: throws XMLStreamException {
395: try {
396: _document.setXmlVersion(version);
397: // XXX encoding
398: } catch (DOMException e) {
399: throw new XMLStreamException(e);
400: }
401: }
402:
403: public void writeStartElement(String localName)
404: throws XMLStreamException {
405: if (_currentIsEmpty) {
406: popContext();
407: _currentIsEmpty = false;
408: }
409:
410: try {
411: Node parent = _current;
412: _current = _document.createElement(localName);
413: parent.appendChild(_current);
414:
415: if (!(parent instanceof Document))
416: pushContext();
417:
418: _currentIsEmpty = false;
419: } catch (DOMException e) {
420: throw new XMLStreamException(e);
421: }
422: }
423:
424: public void writeStartElement(String namespaceURI, String localName)
425: throws XMLStreamException {
426: if (_currentIsEmpty) {
427: popContext();
428: _currentIsEmpty = false;
429: }
430:
431: try {
432: String qname = localName;
433:
434: if (_repair) {
435: String prefix = _tracker.declare(namespaceURI);
436:
437: if (prefix != null)
438: qname = prefix + ':' + localName;
439: } else {
440: String prefix = _tracker.getPrefix(namespaceURI);
441:
442: if (prefix == null)
443: throw new XMLStreamException(L.l(
444: "No prefix defined for namespace {0}",
445: namespaceURI));
446:
447: qname = prefix + ':' + localName;
448: }
449:
450: Node parent = _current;
451: _current = _document.createElementNS(namespaceURI, qname);
452: parent.appendChild(_current);
453:
454: if (!(parent instanceof Document))
455: pushContext();
456:
457: _currentIsEmpty = false;
458: } catch (DOMException e) {
459: throw new XMLStreamException(e);
460: }
461: }
462:
463: public void writeStartElement(String prefix, String localName,
464: String namespaceURI) throws XMLStreamException {
465: if (_currentIsEmpty) {
466: popContext();
467: _currentIsEmpty = false;
468: }
469:
470: try {
471: if (_repair && _tracker.getPrefix(namespaceURI) == null)
472: _tracker.declare(prefix, namespaceURI, true);
473:
474: Node parent = _current;
475: String qname = prefix + ':' + localName;
476: _current = _document.createElementNS(namespaceURI, qname);
477: parent.appendChild(_current);
478:
479: if (!(parent instanceof Document))
480: pushContext();
481:
482: _currentIsEmpty = false;
483: } catch (DOMException e) {
484: throw new XMLStreamException(e);
485: }
486: }
487:
488: //////////////////////////////////////////////////////////////////////////
489:
490: private boolean _flushed = true;
491:
492: private void pushContext() throws DOMException {
493: _tracker.push();
494: _flushed = false;
495: }
496:
497: private void popContext() throws DOMException, XMLStreamException {
498: _tracker.pop();
499: _current = _current.getParentNode();
500: }
501: }
|