1 /*--------------------------------------------------------------------------
\r
2 * Copyright 2004 Taro L. Saito
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 *--------------------------------------------------------------------------*/
\r
16 //-----------------------------------
\r
19 // XMLGenerator.java
\r
20 // Since: 2005/01/16
\r
23 //--------------------------------------
\r
24 package org.xerial.util.xml;
\r
26 import java.io.OutputStream;
\r
27 import java.io.PrintWriter;
\r
28 import java.io.Writer;
\r
29 import java.util.HashMap;
\r
30 import java.util.LinkedList;
\r
32 import org.xerial.core.XerialError;
\r
35 * XML Generator produces well-formed XML documents
\r
37 * <library>[s1](1) [1]<book>[s1] <title>[s2] </title>(2) <author> [s3]</author>
\r
38 * [s4]</book> <name> </name> </library>
\r
40 * (1) newline before nested element (2) newline after leaf element [1] indent
\r
41 * before element (indent string SPACE or TAB, indent character size = 2)
\r
46 * A (the previous output is starg tag) B (the previous output is text content)
\r
47 * C (the previous output is end tag)
\r
49 * TODO: on/off of indentation
\r
53 public class XMLGenerator
\r
55 public enum IndentType {
\r
59 private int _currentLevel = 0;
\r
60 private String _indent = " ";
\r
61 private PrintWriter _out;
\r
62 private LinkedList<String> _tagStack = new LinkedList<String>();
\r
64 public enum FormatStab {
\r
65 NewlineBeforeNestedElement, NewlineAfterElement, IndentBeforeElement
\r
68 private HashMap<FormatStab, Boolean> _formatEnableFlag = new HashMap<FormatStab, Boolean>();
\r
70 private enum PreviousOutput {
\r
71 StartTag, TextContent, EndTag
\r
74 private PreviousOutput _prevOut = PreviousOutput.EndTag;
\r
76 private boolean isEnable(FormatStab stabType)
\r
78 Boolean b = _formatEnableFlag.get(stabType);
\r
79 return b == null ? false : b;
\r
82 public XMLGenerator text(String textContent)
\r
84 _out.print(textContent);
\r
86 _prevOut = PreviousOutput.TextContent;
\r
91 public XMLGenerator startTag(String tagName)
\r
93 return startTag(tagName, null);
\r
96 void beforeStartTag()
\r
101 if (isEnable(FormatStab.NewlineBeforeNestedElement))
\r
104 if (isEnable(FormatStab.IndentBeforeElement))
\r
105 indent(_currentLevel);
\r
110 public static String replaceWhiteSpaces(String tagName)
\r
112 return tagName.replaceAll("\\s+", "_");
\r
115 public XMLGenerator startTag(String tagName, XMLAttribute attribute)
\r
119 String tag = replaceWhiteSpaces(tagName);
\r
124 if (attribute != null && attribute.length() > 0)
\r
127 _out.print(attribute.toXMLString());
\r
132 _tagStack.add(tag);
\r
133 _prevOut = PreviousOutput.StartTag;
\r
138 public XMLGenerator element(String tagName, String textContent)
\r
140 startTag(tagName, null);
\r
146 public XMLGenerator element(String tagName, XMLAttribute attribute, String textContent)
\r
148 startTag(tagName, attribute);
\r
154 public XMLGenerator selfCloseTag(String tagName)
\r
156 return selfCloseTag(tagName, null);
\r
159 public XMLGenerator selfCloseTag(String tagName, XMLAttribute attribute)
\r
164 _out.print(tagName);
\r
166 if (attribute != null && attribute.length() > 0)
\r
169 _out.print(attribute.toXMLString());
\r
172 if (isEnable(FormatStab.NewlineAfterElement))
\r
175 _prevOut = PreviousOutput.EndTag;
\r
179 public XMLGenerator endTag()
\r
181 if (_currentLevel < 1)
\r
182 throw new XerialError(XMLErrorCode.NO_MORE_TAG_TO_CLOSE);
\r
187 if (isEnable(FormatStab.NewlineBeforeNestedElement))
\r
190 if (isEnable(FormatStab.IndentBeforeElement))
\r
191 indent(_currentLevel - 1);
\r
195 String tagName = _tagStack.getLast();
\r
198 _out.print(tagName);
\r
200 if (isEnable(FormatStab.NewlineAfterElement))
\r
204 _tagStack.removeLast();
\r
205 _prevOut = PreviousOutput.EndTag;
\r
210 public XMLGenerator flush()
\r
216 public void endDocument()
\r
218 while (!_tagStack.isEmpty())
\r
223 private void init()
\r
225 _formatEnableFlag.put(FormatStab.NewlineBeforeNestedElement, true);
\r
226 _formatEnableFlag.put(FormatStab.NewlineAfterElement, true);
\r
227 _formatEnableFlag.put(FormatStab.IndentBeforeElement, true);
\r
230 public XMLGenerator()
\r
233 setOutputStream(System.out);
\r
236 public XMLGenerator(OutputStream out)
\r
239 setOutputStream(out);
\r
242 public XMLGenerator(Writer out)
\r
245 setOutputWriter(out);
\r
248 public void setOutputStream(OutputStream out)
\r
250 _out = new PrintWriter(out);
\r
253 public void setOutputWriter(Writer writer)
\r
255 _out = new PrintWriter(writer);
\r
260 * @param indentType
\r
263 * indent size per level
\r
266 public void setIndentCharacter(IndentType indentType, int length)
\r
268 assert length >= 0;
\r
270 StringBuffer indent = new StringBuffer();
\r
271 switch (indentType)
\r
274 for (int i = 0; i < length; i++)
\r
275 indent.append(" ");
\r
278 for (int i = 0; i < length; i++)
\r
279 indent.append("\t");
\r
282 _indent = indent.toString();
\r
285 protected void indent(int level)
\r
287 for (int i = 0; i < level; i++)
\r
288 _out.print(_indent);
\r
291 protected void newline()
\r