OSDN Git Service

imported from subversion repository
[xerial/xerial-core.git] / src / main / java / org / xerial / util / xml / XMLGenerator.java
1 /*--------------------------------------------------------------------------\r
2  *  Copyright 2004 Taro L. Saito\r
3  *\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
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\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
17 // XerialJ Project\r
18 // \r
19 // XMLGenerator.java \r
20 // Since: 2005/01/16\r
21 //\r
22 // $Author: leo $\r
23 //--------------------------------------\r
24 package org.xerial.util.xml;\r
25 \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
31 \r
32 import org.xerial.core.XerialError;\r
33 \r
34 /**\r
35  * XML Generator produces well-formed XML documents\r
36  * \r
37  * <library>[s1](1) [1]<book>[s1] <title>[s2] </title>(2) <author> [s3]</author>\r
38  * [s4]</book> <name> </name> </library>\r
39  * \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
42  * \r
43  * \r
44  * states:\r
45  * \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
48  * \r
49  * TODO: on/off of indentation\r
50  * \r
51  * @author leo\r
52  */\r
53 public class XMLGenerator\r
54 {\r
55     public enum IndentType {\r
56         SPACE, TAB\r
57     };\r
58 \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
63 \r
64     public enum FormatStab {\r
65         NewlineBeforeNestedElement, NewlineAfterElement, IndentBeforeElement\r
66     };\r
67 \r
68     private HashMap<FormatStab, Boolean> _formatEnableFlag = new HashMap<FormatStab, Boolean>();\r
69 \r
70     private enum PreviousOutput {\r
71         StartTag, TextContent, EndTag\r
72     }\r
73 \r
74     private PreviousOutput _prevOut = PreviousOutput.EndTag;\r
75 \r
76     private boolean isEnable(FormatStab stabType)\r
77     {\r
78         Boolean b = _formatEnableFlag.get(stabType);\r
79         return b == null ? false : b;\r
80     }\r
81 \r
82     public XMLGenerator text(String textContent)\r
83     {\r
84         _out.print(textContent);\r
85 \r
86         _prevOut = PreviousOutput.TextContent;\r
87 \r
88         return this;\r
89     }\r
90 \r
91     public XMLGenerator startTag(String tagName)\r
92     {\r
93         return startTag(tagName, null);\r
94     }\r
95 \r
96     void beforeStartTag()\r
97     {\r
98         switch (_prevOut)\r
99         {\r
100         case StartTag:\r
101             if (isEnable(FormatStab.NewlineBeforeNestedElement))\r
102                 newline();\r
103         case EndTag:\r
104             if (isEnable(FormatStab.IndentBeforeElement))\r
105                 indent(_currentLevel);\r
106             break;\r
107         }\r
108     }\r
109 \r
110     public static String replaceWhiteSpaces(String tagName)\r
111     {\r
112         return tagName.replaceAll("\\s+", "_");\r
113     }\r
114 \r
115     public XMLGenerator startTag(String tagName, XMLAttribute attribute)\r
116     {\r
117         beforeStartTag();\r
118 \r
119         String tag = replaceWhiteSpaces(tagName);\r
120 \r
121         _out.print("<");\r
122         _out.print(tag);\r
123 \r
124         if (attribute != null && attribute.length() > 0)\r
125         {\r
126             _out.print(" ");\r
127             _out.print(attribute.toXMLString());\r
128         }\r
129         _out.print(">");\r
130 \r
131         _currentLevel++;\r
132         _tagStack.add(tag);\r
133         _prevOut = PreviousOutput.StartTag;\r
134 \r
135         return this;\r
136     }\r
137 \r
138     public XMLGenerator element(String tagName, String textContent)\r
139     {\r
140         startTag(tagName, null);\r
141         text(textContent);\r
142         endTag();\r
143         return this;\r
144     }\r
145 \r
146     public XMLGenerator element(String tagName, XMLAttribute attribute, String textContent)\r
147     {\r
148         startTag(tagName, attribute);\r
149         text(textContent);\r
150         endTag();\r
151         return this;\r
152     }\r
153 \r
154     public XMLGenerator selfCloseTag(String tagName)\r
155     {\r
156         return selfCloseTag(tagName, null);\r
157     }\r
158 \r
159     public XMLGenerator selfCloseTag(String tagName, XMLAttribute attribute)\r
160     {\r
161         beforeStartTag();\r
162 \r
163         _out.print("<");\r
164         _out.print(tagName);\r
165 \r
166         if (attribute != null && attribute.length() > 0)\r
167         {\r
168             _out.print(" ");\r
169             _out.print(attribute.toXMLString());\r
170         }\r
171         _out.print("/>");\r
172         if (isEnable(FormatStab.NewlineAfterElement))\r
173             newline();\r
174 \r
175         _prevOut = PreviousOutput.EndTag;\r
176         return this;\r
177     }\r
178 \r
179     public XMLGenerator endTag()\r
180     {\r
181         if (_currentLevel < 1)\r
182             throw new XerialError(XMLErrorCode.NO_MORE_TAG_TO_CLOSE);\r
183 \r
184         switch (_prevOut)\r
185         {\r
186         case StartTag:\r
187             if (isEnable(FormatStab.NewlineBeforeNestedElement))\r
188                 newline();\r
189         case EndTag:\r
190             if (isEnable(FormatStab.IndentBeforeElement))\r
191                 indent(_currentLevel - 1);\r
192             break;\r
193         }\r
194 \r
195         String tagName = _tagStack.getLast();\r
196 \r
197         _out.print("</");\r
198         _out.print(tagName);\r
199         _out.print(">");\r
200         if (isEnable(FormatStab.NewlineAfterElement))\r
201             newline();\r
202 \r
203         _currentLevel--;\r
204         _tagStack.removeLast();\r
205         _prevOut = PreviousOutput.EndTag;\r
206 \r
207         return this;\r
208     }\r
209 \r
210     public XMLGenerator flush()\r
211     {\r
212         _out.flush();\r
213         return this;\r
214     }\r
215 \r
216     public void endDocument()\r
217     {\r
218         while (!_tagStack.isEmpty())\r
219             endTag();\r
220         _out.flush();\r
221     }\r
222 \r
223     private void init()\r
224     {\r
225         _formatEnableFlag.put(FormatStab.NewlineBeforeNestedElement, true);\r
226         _formatEnableFlag.put(FormatStab.NewlineAfterElement, true);\r
227         _formatEnableFlag.put(FormatStab.IndentBeforeElement, true);\r
228     }\r
229 \r
230     public XMLGenerator()\r
231     {\r
232         init();\r
233         setOutputStream(System.out);\r
234     }\r
235 \r
236     public XMLGenerator(OutputStream out)\r
237     {\r
238         init();\r
239         setOutputStream(out);\r
240     }\r
241 \r
242     public XMLGenerator(Writer out)\r
243     {\r
244         init();\r
245         setOutputWriter(out);\r
246     }\r
247 \r
248     public void setOutputStream(OutputStream out)\r
249     {\r
250         _out = new PrintWriter(out);\r
251     }\r
252 \r
253     public void setOutputWriter(Writer writer)\r
254     {\r
255         _out = new PrintWriter(writer);\r
256     }\r
257 \r
258     /**\r
259      * \r
260      * @param indentType\r
261      *            SPACE or TAB\r
262      * @param length\r
263      *            indent size per level\r
264      * \r
265      */\r
266     public void setIndentCharacter(IndentType indentType, int length)\r
267     {\r
268         assert length >= 0;\r
269 \r
270         StringBuffer indent = new StringBuffer();\r
271         switch (indentType)\r
272         {\r
273         case SPACE:\r
274             for (int i = 0; i < length; i++)\r
275                 indent.append(" ");\r
276             break;\r
277         case TAB:\r
278             for (int i = 0; i < length; i++)\r
279                 indent.append("\t");\r
280             break;\r
281         }\r
282         _indent = indent.toString();\r
283     }\r
284 \r
285     protected void indent(int level)\r
286     {\r
287         for (int i = 0; i < level; i++)\r
288             _out.print(_indent);\r
289     }\r
290 \r
291     protected void newline()\r
292     {\r
293         _out.println();\r
294     }\r
295 \r
296 }\r