1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.internal;
17
18 import static org.mybatis.generator.internal.util.messages.Messages.getString;
19
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22
23 import org.mybatis.generator.exception.ShellException;
24 import org.w3c.dom.Attr;
25 import org.w3c.dom.CDATASection;
26 import org.w3c.dom.Comment;
27 import org.w3c.dom.Document;
28 import org.w3c.dom.DocumentType;
29 import org.w3c.dom.Element;
30 import org.w3c.dom.EntityReference;
31 import org.w3c.dom.NamedNodeMap;
32 import org.w3c.dom.Node;
33 import org.w3c.dom.ProcessingInstruction;
34 import org.w3c.dom.Text;
35
36
37
38
39
40
41
42
43
44 public class DomWriter {
45
46 protected PrintWriter printWriter;
47
48 protected boolean isXML11;
49
50 public DomWriter() {
51 super();
52 }
53
54 public synchronized String toString(Document document)
55 throws ShellException {
56 StringWriter sw = new StringWriter();
57 printWriter = new PrintWriter(sw);
58 write(document);
59 return sw.toString();
60 }
61
62 protected Attr[] sortAttributes(NamedNodeMap attrs) {
63
64 int len = (attrs != null) ? attrs.getLength() : 0;
65 Attr[] array = new Attr[len];
66 for (int i = 0; i < len; i++) {
67 array[i] = (Attr) attrs.item(i);
68 }
69 for (int i = 0; i < len - 1; i++) {
70 String name = array[i].getNodeName();
71 int index = i;
72 for (int j = i + 1; j < len; j++) {
73 String curName = array[j].getNodeName();
74 if (curName.compareTo(name) < 0) {
75 name = curName;
76 index = j;
77 }
78 }
79 if (index != i) {
80 Attr temp = array[i];
81 array[i] = array[index];
82 array[index] = temp;
83 }
84 }
85
86 return array;
87
88 }
89
90 protected void normalizeAndPrint(String s, boolean isAttValue) {
91
92 int len = (s != null) ? s.length() : 0;
93 for (int i = 0; i < len; i++) {
94 char c = s.charAt(i);
95 normalizeAndPrint(c, isAttValue);
96 }
97 }
98
99 protected void normalizeAndPrint(char c, boolean isAttValue) {
100
101 switch (c) {
102 case '<':
103 handleLessThan();
104 break;
105 case '>':
106 handleGreaterThan();
107 break;
108 case '&':
109 handleAmpersand();
110 break;
111 case '"':
112 handleDoubleQuote(isAttValue);
113 break;
114 case '\r':
115 handleCarriageReturn();
116 break;
117 case '\n':
118 handleLineFeed();
119 break;
120 default:
121 handleDefault(c, isAttValue);
122 }
123 }
124
125 private void handleDefault(char c, boolean isAttValue) {
126
127
128
129
130
131
132
133
134
135
136 if (isXML11
137 && ((c >= 0x01 && c <= 0x1F && c != 0x09 && c != 0x0A)
138 || (c >= 0x7F && c <= 0x9F) || c == 0x2028)
139 || isAttValue && (c == 0x09 || c == 0x0A)) {
140 printWriter.print("&#x");
141 printWriter.print(Integer.toHexString(c).toUpperCase());
142 printWriter.print(';');
143 } else {
144 printWriter.print(c);
145 }
146 }
147
148 private void handleLineFeed() {
149
150
151
152
153
154 printWriter.print(System.getProperty("line.separator"));
155 }
156
157 private void handleCarriageReturn() {
158
159
160
161
162 printWriter.print("
");
163 }
164
165 private void handleDoubleQuote(boolean isAttValue) {
166
167
168 if (isAttValue) {
169 printWriter.print(""");
170 } else {
171 printWriter.print('"');
172 }
173 }
174
175 private void handleAmpersand() {
176 printWriter.print("&");
177 }
178
179 private void handleGreaterThan() {
180 printWriter.print(">");
181 }
182
183 private void handleLessThan() {
184 printWriter.print("<");
185 }
186
187
188
189
190
191
192
193
194 protected String getVersion(Document document) {
195 if (document == null) {
196 return null;
197 }
198
199 return document.getXmlVersion();
200 }
201
202 protected void writeAnyNode(Node node) throws ShellException {
203
204 if (node == null) {
205 return;
206 }
207
208 short type = node.getNodeType();
209 switch (type) {
210 case Node.DOCUMENT_NODE:
211 write((Document) node);
212 break;
213
214 case Node.DOCUMENT_TYPE_NODE:
215 write((DocumentType) node);
216 break;
217
218 case Node.ELEMENT_NODE:
219 write((Element) node);
220 break;
221
222 case Node.ENTITY_REFERENCE_NODE:
223 write((EntityReference) node);
224 break;
225
226 case Node.CDATA_SECTION_NODE:
227 write((CDATASection) node);
228 break;
229
230 case Node.TEXT_NODE:
231 write((Text) node);
232 break;
233
234 case Node.PROCESSING_INSTRUCTION_NODE:
235 write((ProcessingInstruction) node);
236 break;
237
238 case Node.COMMENT_NODE:
239 write((Comment) node);
240 break;
241
242 default:
243 throw new ShellException(getString(
244 "RuntimeError.18", Short.toString(type)));
245 }
246 }
247
248 protected void write(Document node) throws ShellException {
249 isXML11 = "1.1".equals(getVersion(node));
250 if (isXML11) {
251 printWriter.println("<?xml version=\"1.1\" encoding=\"UTF-8\"?>");
252 } else {
253 printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
254 }
255 printWriter.flush();
256 write(node.getDoctype());
257 write(node.getDocumentElement());
258 }
259
260 protected void write(DocumentType node) {
261 printWriter.print("<!DOCTYPE ");
262 printWriter.print(node.getName());
263 String publicId = node.getPublicId();
264 String systemId = node.getSystemId();
265 if (publicId != null) {
266 printWriter.print(" PUBLIC \"");
267 printWriter.print(publicId);
268 printWriter.print("\" \"");
269 printWriter.print(systemId);
270 printWriter.print('\"');
271 } else if (systemId != null) {
272 printWriter.print(" SYSTEM \"");
273 printWriter.print(systemId);
274 printWriter.print('"');
275 }
276
277 String internalSubset = node.getInternalSubset();
278 if (internalSubset != null) {
279 printWriter.println(" [");
280 printWriter.print(internalSubset);
281 printWriter.print(']');
282 }
283 printWriter.println('>');
284 }
285
286 protected void write(Element node) throws ShellException {
287 printWriter.print('<');
288 printWriter.print(node.getNodeName());
289 Attr[] attrs = sortAttributes(node.getAttributes());
290 for (Attr attr : attrs) {
291 printWriter.print(' ');
292 printWriter.print(attr.getNodeName());
293 printWriter.print("=\"");
294 normalizeAndPrint(attr.getNodeValue(), true);
295 printWriter.print('"');
296 }
297
298 if (node.getChildNodes().getLength() == 0) {
299 printWriter.print(" />");
300 printWriter.flush();
301 } else {
302 printWriter.print('>');
303 printWriter.flush();
304
305 Node child = node.getFirstChild();
306 while (child != null) {
307 writeAnyNode(child);
308 child = child.getNextSibling();
309 }
310
311 printWriter.print("</");
312 printWriter.print(node.getNodeName());
313 printWriter.print('>');
314 printWriter.flush();
315 }
316 }
317
318 protected void write(EntityReference node) {
319 printWriter.print('&');
320 printWriter.print(node.getNodeName());
321 printWriter.print(';');
322 printWriter.flush();
323 }
324
325 protected void write(CDATASection node) {
326 printWriter.print("<![CDATA[");
327 String data = node.getNodeValue();
328
329
330
331 int len = (data != null) ? data.length() : 0;
332 for (int i = 0; i < len; i++) {
333 char c = data.charAt(i);
334 if (c == '\n') {
335 handleLineFeed();
336 } else {
337 printWriter.print(c);
338 }
339 }
340 printWriter.print("]]>");
341 printWriter.flush();
342 }
343
344 protected void write(Text node) {
345 normalizeAndPrint(node.getNodeValue(), false);
346 printWriter.flush();
347 }
348
349 protected void write(ProcessingInstruction node) {
350 printWriter.print("<?");
351 printWriter.print(node.getNodeName());
352 String data = node.getNodeValue();
353 if (data != null && data.length() > 0) {
354 printWriter.print(' ');
355 printWriter.print(data);
356 }
357 printWriter.print("?>");
358 printWriter.flush();
359 }
360
361 protected void write(Comment node) {
362 printWriter.print("<!--");
363 String comment = node.getNodeValue();
364 if (comment != null && comment.length() > 0) {
365 normalizeAndPrint(comment, false);
366 }
367 printWriter.print("-->");
368 printWriter.flush();
369 }
370 }