IndentingXMLStreamWriter.java
001 /*
002  * Java GPX Library (jpx-3.1.0).
003  * Copyright (c) 2016-2023 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.jpx;
021 
022 import java.util.ArrayDeque;
023 import java.util.Deque;
024 
025 import javax.xml.stream.XMLStreamException;
026 import javax.xml.stream.XMLStreamWriter;
027 
028 /**
029  {@link XMLStreamWriter} proxy for writing XML indentations.
030  *
031  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
032  @version 1.0
033  @since 1.0
034  */
035 final class IndentingXMLStreamWriter extends XMLStreamWriterAdapter {
036 
037     private enum State {
038         SEEN_NOTHING,
039         SEEN_ELEMENT,
040         SEEN_DATA
041     }
042 
043     private static final String NEW_LINE = System.lineSeparator();
044 
045     private State _state;
046     private final Deque<State> _states = new ArrayDeque<>();
047     private final String _indent;
048     private int _depth;
049 
050     IndentingXMLStreamWriter(final XMLStreamWriter writer, final String indent) {
051         super(writer);
052         _state = State.SEEN_NOTHING;
053         _indent = indent;
054         _depth = 0;
055     }
056 
057     private void onStartElement() throws XMLStreamException {
058         _states.push(State.SEEN_ELEMENT);
059         _state = State.SEEN_NOTHING;
060         if (_depth > 0) {
061             super.writeCharacters(NEW_LINE);
062         }
063 
064         doIndent();
065         ++_depth;
066     }
067 
068     private void onEndElement() throws XMLStreamException {
069         --_depth;
070         if (_state == State.SEEN_ELEMENT) {
071             super.writeCharacters(NEW_LINE);
072             doIndent();
073         }
074 
075         _state = _states.pop();
076     }
077 
078     private void onEmptyElement() throws XMLStreamException {
079         _state = State.SEEN_ELEMENT;
080         if(_depth > 0) {
081             super.writeCharacters(NEW_LINE);
082         }
083 
084         doIndent();
085     }
086 
087     private void doIndent() throws XMLStreamException {
088         if (_depth > 0) {
089             for(int i = 0; i < _depth; ++i) {
090                 super.writeCharacters(_indent);
091             }
092         }
093 
094     }
095 
096     @Override
097     public void writeStartDocument() throws XMLStreamException {
098         super.writeStartDocument();
099         super.writeCharacters(NEW_LINE);
100     }
101 
102     @Override
103     public void writeStartDocument(final String version)
104         throws XMLStreamException
105     {
106         super.writeStartDocument(version);
107         super.writeCharacters(NEW_LINE);
108     }
109 
110     @Override
111     public void writeStartDocument(final String encoding, final String version)
112         throws XMLStreamException
113     {
114         super.writeStartDocument(encoding, version);
115         super.writeCharacters(NEW_LINE);
116     }
117 
118     @Override
119     public void writeStartElement(final String localName)
120         throws XMLStreamException
121     {
122         onStartElement();
123         super.writeStartElement(localName);
124     }
125 
126     @Override
127     public void writeStartElement(
128         final String namespaceURI,
129         final String localName
130     )
131         throws XMLStreamException
132     {
133         onStartElement();
134         super.writeStartElement(namespaceURI, localName);
135     }
136 
137     @Override
138     public void writeStartElement(
139         final String prefix,
140         final String localName,
141         final String namespaceURI
142     )
143         throws XMLStreamException
144     {
145         onStartElement();
146         super.writeStartElement(prefix, localName, namespaceURI);
147     }
148 
149     @Override
150     public void writeEmptyElement(
151         final String namespaceURI,
152         final String localName
153     )
154         throws XMLStreamException
155     {
156         onEmptyElement();
157         super.writeEmptyElement(namespaceURI, localName);
158     }
159 
160     @Override
161     public void writeEmptyElement(
162         final String prefix,
163         final String localName,
164         final String namespaceURI
165     )
166         throws XMLStreamException
167     {
168         onEmptyElement();
169         super.writeEmptyElement(prefix, localName, namespaceURI);
170     }
171 
172     @Override
173     public void writeEmptyElement(final String localName)
174         throws XMLStreamException
175     {
176         onEmptyElement();
177         super.writeEmptyElement(localName);
178     }
179 
180     @Override
181     public void writeEndElement() throws XMLStreamException {
182         onEndElement();
183         super.writeEndElement();
184     }
185 
186     @Override
187     public void writeCharacters(final String textthrows XMLStreamException {
188         _state = State.SEEN_DATA;
189         super.writeCharacters(text);
190     }
191 
192     @Override
193     public void writeCharacters(
194         final char[] text,
195         final int start,
196         final int len
197     )
198         throws XMLStreamException
199     {
200         _state = State.SEEN_DATA;
201         super.writeCharacters(text, start, len);
202     }
203 
204     @Override
205     public void writeCData(final String datathrows XMLStreamException {
206         _state = State.SEEN_DATA;
207         super.writeCData(data);
208     }
209 }