@@ -51,10 +51,23 @@ private Marshaller createMarshaller() throws JAXBException {
5151 * @param output OutputStream
5252 */
5353 public void encode (Mapml mapml , OutputStream output ) {
54+ encode (mapml , output , false );
55+ }
56+
57+ /**
58+ * Use Marshaller to encode MapML object onto an output stream with optional pretty-printing
59+ *
60+ * @param mapml MapML object
61+ * @param output OutputStream
62+ * @param prettyPrint true to enable pretty-printing with 2-space indents, false for dense markup
63+ */
64+ public void encode (Mapml mapml , OutputStream output , boolean prettyPrint ) {
5465 try {
55- XMLStreamWriter writer = new Wrapper (XMLOutputFactory .newInstance ().createXMLStreamWriter (output ));
56- createMarshaller ().marshal (mapml , writer );
57- writer .flush ();
66+ XMLOutputFactory factory = XMLOutputFactory .newInstance ();
67+ Wrapper wrapper = new Wrapper (factory .createXMLStreamWriter (output ));
68+ wrapper .setIndenting (prettyPrint );
69+ createMarshaller ().marshal (mapml , wrapper );
70+ wrapper .flush ();
5871 } catch (JAXBException | XMLStreamException e ) {
5972 throw new ServiceException (e );
6073 }
@@ -81,6 +94,13 @@ static class Wrapper implements XMLStreamWriter {
8194
8295 private final XMLStreamWriter writer ;
8396 private static final String NS_PREFIX = "" ;
97+ public static final String MAPML_INDENT_PROPERTY = "mapml.indent" ;
98+ private static final String INDENT = " " ;
99+
100+ private boolean indenting = false ;
101+ private int depth = 0 ;
102+ private boolean needsIndent = false ;
103+ private boolean lastWasStartElement = false ;
84104
85105 /**
86106 * Constructor
@@ -91,39 +111,90 @@ static class Wrapper implements XMLStreamWriter {
91111 this .writer = writer ;
92112 }
93113
114+ /** Writes indentation if pretty-printing is enabled */
115+ private void writeIndent () throws XMLStreamException {
116+ if (indenting && needsIndent ) {
117+ writer .writeCharacters ("\n " );
118+ for (int i = 0 ; i < depth ; i ++) {
119+ writer .writeCharacters (INDENT );
120+ }
121+ needsIndent = false ;
122+ }
123+ }
124+
94125 @ Override
95126 public void writeStartElement (String localName ) throws XMLStreamException {
127+ writeIndent ();
96128 writer .writeStartElement (localName );
129+ depth ++;
130+ needsIndent = true ;
131+ lastWasStartElement = true ;
97132 }
98133
99134 @ Override
100135 public void writeStartElement (String namespaceURI , String localName ) throws XMLStreamException {
136+ writeIndent ();
101137 writer .writeStartElement (namespaceURI , localName );
138+ depth ++;
139+ needsIndent = true ;
140+ lastWasStartElement = true ;
102141 }
103142
104143 @ Override
105144 public void writeStartElement (String prefix , String localName , String namespaceURI ) throws XMLStreamException {
145+ writeIndent ();
106146 writer .writeStartElement (NS_PREFIX , localName , namespaceURI );
147+ depth ++;
148+ needsIndent = true ;
149+ lastWasStartElement = true ;
107150 }
108151
109152 @ Override
110153 public void writeEmptyElement (String namespaceURI , String localName ) throws XMLStreamException {
111- writer .writeEmptyElement (namespaceURI , localName );
154+ // Force HTML-compatible empty elements with explicit end tags
155+ writeIndent ();
156+ writer .writeStartElement (namespaceURI , localName );
157+ writer .writeEndElement ();
158+ needsIndent = true ;
112159 }
113160
114161 @ Override
115162 public void writeEmptyElement (String prefix , String localName , String namespaceURI ) throws XMLStreamException {
116- writer .writeEmptyElement (prefix , localName , namespaceURI );
163+ // Force HTML-compatible empty elements with explicit end tags
164+ writeIndent ();
165+ writer .writeStartElement (NS_PREFIX , localName , namespaceURI );
166+ writer .writeEndElement ();
167+ needsIndent = true ;
117168 }
118169
119170 @ Override
120171 public void writeEmptyElement (String localName ) throws XMLStreamException {
121- writer .writeEmptyElement (localName );
172+ // Force HTML-compatible empty elements with explicit end tags
173+ writeIndent ();
174+ writer .writeStartElement (localName );
175+ writer .writeEndElement ();
176+ needsIndent = true ;
122177 }
123178
124179 @ Override
125180 public void writeEndElement () throws XMLStreamException {
181+ depth --;
182+ // For empty elements (start immediately followed by end), keep on same line
183+ if (needsIndent && !lastWasStartElement ) {
184+ writeIndent ();
185+ } else if (lastWasStartElement ) {
186+ // Note: empty string typically doesn't add content but signals "non-empty" to writer
187+ writer .writeCharacters ("" );
188+ }
126189 writer .writeEndElement ();
190+
191+ // Add two newlines after the root closing tag
192+ if (depth == 0 && indenting ) {
193+ writer .writeCharacters ("\n \n " );
194+ }
195+
196+ needsIndent = true ;
197+ lastWasStartElement = false ;
127198 }
128199
129200 @ Override
@@ -169,7 +240,9 @@ public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException
169240
170241 @ Override
171242 public void writeComment (String data ) throws XMLStreamException {
243+ writeIndent ();
172244 writer .writeComment (data );
245+ needsIndent = true ;
173246 }
174247
175248 @ Override
@@ -214,11 +287,17 @@ public void writeStartDocument(String encoding, String version) throws XMLStream
214287
215288 @ Override
216289 public void writeCharacters (String text ) throws XMLStreamException {
290+ // Don't indent before text content as it would alter the actual content
291+ needsIndent = false ;
292+ lastWasStartElement = false ;
217293 writer .writeCharacters (text );
218294 }
219295
220296 @ Override
221297 public void writeCharacters (char [] text , int start , int len ) throws XMLStreamException {
298+ // Don't indent before text content as it would alter the actual content
299+ needsIndent = false ;
300+ lastWasStartElement = false ;
222301 writer .writeCharacters (text , start , len );
223302 }
224303
@@ -249,7 +328,28 @@ public NamespaceContext getNamespaceContext() {
249328
250329 @ Override
251330 public Object getProperty (String name ) throws IllegalArgumentException {
331+ if (MAPML_INDENT_PROPERTY .equals (name )) {
332+ return indenting ;
333+ }
252334 return writer .getProperty (name );
253335 }
336+
337+ /**
338+ * Sets the indenting property for pretty-printing
339+ *
340+ * @param indent true to enable pretty-printing with 2-space indents, false for dense markup
341+ */
342+ public void setIndenting (boolean indent ) {
343+ this .indenting = indent ;
344+ }
345+
346+ /**
347+ * Gets the current indenting state
348+ *
349+ * @return true if pretty-printing is enabled
350+ */
351+ public boolean isIndenting () {
352+ return indenting ;
353+ }
254354 }
255355}
0 commit comments