1
2
3
4
5
6 package dev.metaschema.schemagen.xml.impl;
7
8 import java.util.ArrayDeque;
9 import java.util.Deque;
10
11 import javax.xml.namespace.NamespaceContext;
12 import javax.xml.stream.XMLStreamException;
13 import javax.xml.stream.XMLStreamWriter;
14
15 import edu.umd.cs.findbugs.annotations.NonNull;
16
17
18
19
20
21
22
23
24
25
26
27
28 public class IndentingXMLStreamWriter implements XMLStreamWriter, AutoCloseable {
29
30 private static final String NEWLINE = "\n";
31 private static final String INDENT = " ";
32
33 @NonNull
34 private final XMLStreamWriter delegate;
35
36 private int depth;
37 private final Deque<Boolean> hasTextStack = new ArrayDeque<>();
38 private boolean hasText;
39 private boolean lastWasStart;
40
41
42
43
44
45
46
47 public IndentingXMLStreamWriter(@NonNull XMLStreamWriter delegate) {
48 this.delegate = delegate;
49 this.depth = 0;
50 this.hasText = false;
51 this.lastWasStart = false;
52 }
53
54
55
56
57
58
59
60 private void writeIndent() throws XMLStreamException {
61 delegate.writeCharacters(NEWLINE);
62 for (int i = 0; i < depth; i++) {
63 delegate.writeCharacters(INDENT);
64 }
65 }
66
67 @Override
68 public void writeStartElement(String localName) throws XMLStreamException {
69 prepareStartElement();
70 delegate.writeStartElement(localName);
71 afterStartElement();
72 }
73
74 @Override
75 public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
76 prepareStartElement();
77 delegate.writeStartElement(namespaceURI, localName);
78 afterStartElement();
79 }
80
81 @Override
82 public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
83 prepareStartElement();
84 delegate.writeStartElement(prefix, localName, namespaceURI);
85 afterStartElement();
86 }
87
88
89
90
91
92
93
94 private void prepareStartElement() throws XMLStreamException {
95 if (!hasText) {
96 writeIndent();
97 }
98 hasTextStack.push(hasText);
99 }
100
101
102
103
104 private void afterStartElement() {
105 depth++;
106 hasText = false;
107 lastWasStart = true;
108 }
109
110 @Override
111 public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
112 if (!hasText) {
113 writeIndent();
114 }
115 delegate.writeEmptyElement(namespaceURI, localName);
116 lastWasStart = false;
117 }
118
119 @Override
120 public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
121 if (!hasText) {
122 writeIndent();
123 }
124 delegate.writeEmptyElement(prefix, localName, namespaceURI);
125 lastWasStart = false;
126 }
127
128 @Override
129 public void writeEmptyElement(String localName) throws XMLStreamException {
130 if (!hasText) {
131 writeIndent();
132 }
133 delegate.writeEmptyElement(localName);
134 lastWasStart = false;
135 }
136
137 @Override
138 public void writeEndElement() throws XMLStreamException {
139 depth--;
140 boolean parentHasText = !hasTextStack.isEmpty() && hasTextStack.pop();
141
142 if (!hasText && !lastWasStart) {
143 writeIndent();
144 }
145 delegate.writeEndElement();
146 hasText = parentHasText;
147 lastWasStart = false;
148 }
149
150 @Override
151 public void writeEndDocument() throws XMLStreamException {
152 delegate.writeEndDocument();
153 }
154
155 @Override
156 public void close() throws XMLStreamException {
157 delegate.close();
158 }
159
160 @Override
161 public void flush() throws XMLStreamException {
162 delegate.flush();
163 }
164
165 @Override
166 public void writeAttribute(String localName, String value) throws XMLStreamException {
167 delegate.writeAttribute(localName, value);
168 }
169
170 @Override
171 public void writeAttribute(String prefix, String namespaceURI, String localName, String value)
172 throws XMLStreamException {
173 delegate.writeAttribute(prefix, namespaceURI, localName, value);
174 }
175
176 @Override
177 public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException {
178 delegate.writeAttribute(namespaceURI, localName, value);
179 }
180
181 @Override
182 public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
183 delegate.writeNamespace(prefix, namespaceURI);
184 }
185
186 @Override
187 public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
188 delegate.writeDefaultNamespace(namespaceURI);
189 }
190
191 @Override
192 public void writeComment(String data) throws XMLStreamException {
193 if (!hasText) {
194 writeIndent();
195 }
196 delegate.writeComment(data);
197 lastWasStart = false;
198 }
199
200 @Override
201 public void writeProcessingInstruction(String target) throws XMLStreamException {
202 if (!hasText) {
203 writeIndent();
204 }
205 delegate.writeProcessingInstruction(target);
206 lastWasStart = false;
207 }
208
209 @Override
210 public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
211 if (!hasText) {
212 writeIndent();
213 }
214 delegate.writeProcessingInstruction(target, data);
215 lastWasStart = false;
216 }
217
218 @Override
219 public void writeCData(String data) throws XMLStreamException {
220 delegate.writeCData(data);
221 hasText = true;
222 lastWasStart = false;
223 }
224
225 @Override
226 public void writeDTD(String dtd) throws XMLStreamException {
227 delegate.writeDTD(dtd);
228 }
229
230 @Override
231 public void writeEntityRef(String name) throws XMLStreamException {
232 delegate.writeEntityRef(name);
233 hasText = true;
234 lastWasStart = false;
235 }
236
237 @Override
238 public void writeStartDocument() throws XMLStreamException {
239 delegate.writeStartDocument();
240 }
241
242 @Override
243 public void writeStartDocument(String version) throws XMLStreamException {
244 delegate.writeStartDocument(version);
245 }
246
247 @Override
248 public void writeStartDocument(String encoding, String version) throws XMLStreamException {
249 delegate.writeStartDocument(encoding, version);
250 }
251
252 @Override
253 public void writeCharacters(String text) throws XMLStreamException {
254 delegate.writeCharacters(text);
255 hasText = true;
256 lastWasStart = false;
257 }
258
259 @Override
260 public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
261 delegate.writeCharacters(text, start, len);
262 hasText = true;
263 lastWasStart = false;
264 }
265
266 @Override
267 public String getPrefix(String uri) throws XMLStreamException {
268 return delegate.getPrefix(uri);
269 }
270
271 @Override
272 public void setPrefix(String prefix, String uri) throws XMLStreamException {
273 delegate.setPrefix(prefix, uri);
274 }
275
276 @Override
277 public void setDefaultNamespace(String uri) throws XMLStreamException {
278 delegate.setDefaultNamespace(uri);
279 }
280
281 @Override
282 public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
283 delegate.setNamespaceContext(context);
284 }
285
286 @Override
287 public NamespaceContext getNamespaceContext() {
288 return delegate.getNamespaceContext();
289 }
290
291 @Override
292 public Object getProperty(String name) {
293 return delegate.getProperty(name);
294 }
295 }