| Class | Line # | Actions | |||||
|---|---|---|---|---|---|---|---|
| XMLWriter | 52 | 28 | 0% | 14 | 12 |
| 1 | /* | |
| 2 | * See the NOTICE file distributed with this work for additional | |
| 3 | * information regarding copyright ownership. | |
| 4 | * | |
| 5 | * This is free software; you can redistribute it and/or modify it | |
| 6 | * under the terms of the GNU Lesser General Public License as | |
| 7 | * published by the Free Software Foundation; either version 2.1 of | |
| 8 | * the License, or (at your option) any later version. | |
| 9 | * | |
| 10 | * This software is distributed in the hope that it will be useful, | |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 | * Lesser General Public License for more details. | |
| 14 | * | |
| 15 | * You should have received a copy of the GNU Lesser General Public | |
| 16 | * License along with this software; if not, write to the Free | |
| 17 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
| 18 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
| 19 | */ | |
| 20 | package com.xpn.xwiki.internal.xml; | |
| 21 | ||
| 22 | import java.io.IOException; | |
| 23 | import java.io.InputStream; | |
| 24 | import java.io.OutputStream; | |
| 25 | import java.io.Reader; | |
| 26 | import java.io.UnsupportedEncodingException; | |
| 27 | import java.util.Stack; | |
| 28 | ||
| 29 | import org.apache.commons.codec.binary.Base64OutputStream; | |
| 30 | import org.apache.commons.io.IOUtils; | |
| 31 | import org.apache.commons.io.output.CloseShieldOutputStream; | |
| 32 | import org.dom4j.Document; | |
| 33 | import org.dom4j.Element; | |
| 34 | import org.dom4j.io.OutputFormat; | |
| 35 | ||
| 36 | /** | |
| 37 | * Extension to <code>{@link org.dom4j.io.XMLWriter}</code> to allow filling some element content with an input stream, | |
| 38 | * minimizing the memory footprint of the operation. | |
| 39 | * <p> | |
| 40 | * This extension is not intended to be used to format a DOM4J tree to a stream, but to immediately write out the tags | |
| 41 | * produced without building the document tree in memory. It is not compatible with the SAX part of the original | |
| 42 | * <code>{@link org.dom4j.io.XMLWriter}</code>. | |
| 43 | * </p> | |
| 44 | * <p> | |
| 45 | * An improvement to the writeOpen/writeClose functions ensure better handling of independent opening and closing of | |
| 46 | * tags by maintaining a state stack of opened tags. New writeDocumentStart/End function also ensure proper starting and | |
| 47 | * ending of the document it self. | |
| 48 | * </p> | |
| 49 | * | |
| 50 | * @version $Id: cb5a6e08619da9ffe54b8833cdaa0dcd887c770b $ | |
| 51 | */ | |
| 52 | public class XMLWriter extends org.dom4j.io.XMLWriter | |
| 53 | { | |
| 54 | /** | |
| 55 | * <code>{@link Stack}</code> of currently opened <code>{@link Element}</code>, the first | |
| 56 | * <code>{@link Element}</code> is the document root element, and the top of the stack is the last opened | |
| 57 | * <code>{@link Element}</code>. | |
| 58 | */ | |
| 59 | protected Stack<Element> parent = new Stack<Element>(); | |
| 60 | ||
| 61 | /** | |
| 62 | * Current <code>{@link OutputStream}</code> of this writer. | |
| 63 | */ | |
| 64 | private OutputStream out; | |
| 65 | ||
| 66 | /** | |
| 67 | * Default constructor used by <code>{@link DOMXMLWriter}</code>. | |
| 68 | * | |
| 69 | * @see DOMXMLWriter | |
| 70 | */ | |
| 71 | 3 | protected XMLWriter() |
| 72 | { | |
| 73 | } | |
| 74 | ||
| 75 | /** | |
| 76 | * Create a new XMLWriter writing to a provided OutputStream in a given format. Note that other constructor of the | |
| 77 | * original DOM4J XMLWriter are unsupported since a OutputStream is the only way we can support the extensions | |
| 78 | * provided here. | |
| 79 | * <p> | |
| 80 | * Note that the writer is buffered and only a call to flush() or writeDocuemntEnd() will ensure the output has been | |
| 81 | * fully written to the <code>{@link OutputStream}</code>. | |
| 82 | * </p> | |
| 83 | * | |
| 84 | * @param out an <code>{@link OutputStream}</code> where to output the XML produced. | |
| 85 | * @param format an <code>{@link OutputFormat}</code> defining the encoding that should be used and esthetics of the | |
| 86 | * produced XML. | |
| 87 | * @throws UnsupportedEncodingException the requested encoding is unsupported. | |
| 88 | */ | |
| 89 | 63 | public XMLWriter(OutputStream out, OutputFormat format) throws UnsupportedEncodingException |
| 90 | { | |
| 91 | 63 | super(out, format); |
| 92 | 63 | this.out = out; |
| 93 | } | |
| 94 | ||
| 95 | /** | |
| 96 | * Write the <code>{@link Document}</code> declaration, and its <code>{@link org.dom4j.DocumentType}</code> if | |
| 97 | * available to the output stream. | |
| 98 | * | |
| 99 | * @param doc <code>{@link Document}</code> to be started, may specify a <code>{@link org.dom4j.DocumentType}</code> | |
| 100 | * . | |
| 101 | * @throws IOException a problem occurs during writing | |
| 102 | */ | |
| 103 | 63 | public void writeDocumentStart(Document doc) throws IOException |
| 104 | { | |
| 105 | 63 | writeDeclaration(); |
| 106 | ||
| 107 | 63 | if (doc.getDocType() != null) { |
| 108 | 0 | indent(); |
| 109 | 0 | writeDocType(doc.getDocType()); |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | /** | |
| 114 | * Close all remaining opened <code>{@link Element}</code> including the root element to terminate the current | |
| 115 | * document. Also flush the writer to ensure the whole document has been written to the | |
| 116 | * <code>{@link OutputStream}</code>. | |
| 117 | * | |
| 118 | * @param doc <code>{@link Document}</code> to be end, actually unused. | |
| 119 | * @throws IOException a problem occurs during writing. | |
| 120 | */ | |
| 121 | 63 | public void writeDocumentEnd(Document doc) throws IOException |
| 122 | { | |
| 123 | 63 | if (!this.parent.isEmpty()) { |
| 124 | 1 | writeClose(this.parent.firstElement()); |
| 125 | } | |
| 126 | 63 | writePrintln(); |
| 127 | 63 | flush(); |
| 128 | } | |
| 129 | ||
| 130 | /** | |
| 131 | * Writes the <code>{@link Element}</code>, including its <code>{@link | |
| 132 | * org.dom4j.Attribute}</code>s, using the <code>{@link Reader}</code> for its content. | |
| 133 | * <p> | |
| 134 | * Note that proper decoding/encoding will occurs during this operation, converting the encoding of the Reader into | |
| 135 | * the encoding of the Writer. | |
| 136 | * </p> | |
| 137 | * | |
| 138 | * @param element <code>{@link Element}</code> to output. | |
| 139 | * @param rd <code>{@link Reader}</code> that will be fully read and transfered into the element content. | |
| 140 | * @throws IOException a problem occurs during reading or writing. | |
| 141 | */ | |
| 142 | 0 | public void write(Element element, Reader rd) throws IOException |
| 143 | { | |
| 144 | 0 | writeOpen(element); |
| 145 | 0 | IOUtils.copy(rd, this.writer); |
| 146 | 0 | writeClose(element); |
| 147 | } | |
| 148 | ||
| 149 | /** | |
| 150 | * Writes the <code>{@link Element}</code>, including its <code>{@link | |
| 151 | * org.dom4j.Attribute}</code>s, using the <code>{@link InputStream}</code> for its content. | |
| 152 | * <p> | |
| 153 | * Note that no decoding/encoding of the InputStream will be ensured during this operation. The byte content is | |
| 154 | * transfered untouched. | |
| 155 | * </p> | |
| 156 | * | |
| 157 | * @param element <code>{@link Element}</code> to output. | |
| 158 | * @param is <code>{@link InputStream}</code> that will be fully read and transfered into the element content. | |
| 159 | * @throws IOException a problem occurs during reading or writing. | |
| 160 | */ | |
| 161 | 0 | public void write(Element element, InputStream is) throws IOException |
| 162 | { | |
| 163 | 0 | writeOpen(element); |
| 164 | 0 | flush(); |
| 165 | 0 | IOUtils.copy(is, this.out); |
| 166 | 0 | writeClose(element); |
| 167 | } | |
| 168 | ||
| 169 | /** | |
| 170 | * Writes the <code>{@link Element}</code>, including its <code>{@link | |
| 171 | * org.dom4j.Attribute}</code>s, using the <code>{@link InputStream}</code> encoded in Base64 for its content. | |
| 172 | * | |
| 173 | * @param element <code>{@link Element}</code> to output. | |
| 174 | * @param is <code>{@link InputStream}</code> that will be fully read and encoded in Base64 into the element | |
| 175 | * content. | |
| 176 | * @throws IOException a problem occurs during reading or writing. | |
| 177 | */ | |
| 178 | 62 | public void writeBase64(Element element, InputStream is) throws IOException |
| 179 | { | |
| 180 | 62 | writeOpen(element); |
| 181 | 62 | flush(); |
| 182 | 62 | try (Base64OutputStream base64 = new Base64OutputStream(new CloseShieldOutputStream(this.out))) { |
| 183 | 62 | IOUtils.copy(is, base64); |
| 184 | } | |
| 185 | 62 | writeClose(element); |
| 186 | } | |
| 187 | ||
| 188 | /** | |
| 189 | * Writes the opening tag of an {@link Element}, including its {@link org.dom4j.Attribute}s but without its content. | |
| 190 | * <p> | |
| 191 | * Compared to the DOM4J implementation, this function keeps track of opened elements. | |
| 192 | * </p> | |
| 193 | * | |
| 194 | * @param element <code>{@link Element}</code> to output. | |
| 195 | * @throws IOException a problem occurs during writing. | |
| 196 | * @see org.dom4j.io.XMLWriter#writeOpen(org.dom4j.Element) | |
| 197 | */ | |
| 198 | 126 | @Override |
| 199 | public void writeOpen(Element element) throws IOException | |
| 200 | { | |
| 201 | 126 | super.writeOpen(element); |
| 202 | 126 | this.parent.push(element); |
| 203 | } | |
| 204 | ||
| 205 | /** | |
| 206 | * Writes the closing tag of an {@link Element}. | |
| 207 | * <p> | |
| 208 | * Compared to the DOM4J implementation, this function ensure closing of all opened element including the one that | |
| 209 | * is requested to be closed. | |
| 210 | * </p> | |
| 211 | * | |
| 212 | * @param element <code>{@link Element}</code> to output. | |
| 213 | * @throws IOException a problem occurs during writing. | |
| 214 | * @see org.dom4j.io.XMLWriter#writeClose(org.dom4j.Element) | |
| 215 | */ | |
| 216 | 125 | @Override |
| 217 | public void writeClose(Element element) throws IOException | |
| 218 | { | |
| 219 | 126 | while (this.parent.peek() != element) { |
| 220 | 1 | super.writeClose(this.parent.pop()); |
| 221 | } | |
| 222 | 125 | super.writeClose(this.parent.pop()); |
| 223 | } | |
| 224 | } |