org.simpleframework.xml.stream.Indenter Maven / Gradle / Ivy
Show all versions of simple-xml Show documentation
/*
* Indenter.java July 2006
*
* Copyright (C) 2006, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.xml.stream;
/**
* The Indenter
is used create indent strings using the
* stack paradigm. This allows XML documents to be generated by
* pushing and popping indents onto the stack. This indenter caches
* all indent strings created so that when the same position on the
* stack is encountered the indent can be acquired quickly.
*
* The indents created by this are all prefixed with the line feed
* character, which allows XML tags to span exclusive lines. If the
* indent size specified is zero or less then no spaces, or line
* feed will be added to the generated indent string.
*
* @author Niall Gallagher
*/
class Indenter {
/**
* Provides a quick string cache that caches using by index.
*/
private Cache cache;
/**
* Number of spaces that is used for each of the indents.
*/
private int indent;
/**
* Represents the current number of spaces in the indent text.
*/
private int count;
/**
* Represents the index within the cache to get the indent.
*/
private int index;
/**
* Constructor for the Indenter
object. This will
* create an indent that uses three spaces for each indent that
* is pushed on to the stack. This also uses a default cache
* size of sixteen, which should be sufficient for most files.
*/
public Indenter() {
this(new Format());
}
/**
* Constructor for the Indenter
object. This will
* create an indent that uses the specified number of spaces to
* create each entry pushed on to the stack. This uses a cache
* size of sixteen, which should be sufficient for most files.
*
* @param format determines the number of spaces per indent
*/
public Indenter(Format format) {
this(format, 16);
}
/**
* Constructor for the Indenter
object. This will
* create an indent that uses the specified number of spaces to
* create each entry pushed on to the stack. This uses a cache
* of the specified size, which is used to optimize the object.
*
* @param format determines the number of spaces per indent
* @param size this is the initial size of the indent cache
*/
private Indenter(Format format, int size) {
this.indent = format.getIndent();
this.cache = new Cache(size);
}
/**
* This returns the current indent for this indenter. This should
* be used to write elements or comments that should be at the
* same indentation level as the XML element that will follow.
*
* @return this returns the current indentation level for this
*/
public String top() {
return indent(index);
}
/**
* This is used to push an indent on to the cache. The first
* indent created by this is an empty string, this is because an
* indent is not required for the start of an XML file. If there
* are multiple roots written to the same writer then the start
* and end tags of a root element will exist on the same line.
*
* @return this is used to push an indent on to the stack
*/
public String push() {
String text = indent(index++);
if(indent > 0) {
count += indent;
}
return text;
}
/**
* This is used to pop an indent from the cache. This reduces
* the length of the current indent and is typically used when
* an end tag is added to an XML document. If the number of pop
* requests exceeds the number of push requests then an empty
* string is returned from this method.
*
* @return this is used to pop an indent from the stack
*/
public String pop() {
String text = indent(--index);
if(indent > 0) {
count -= indent;
}
return text;
}
/**
* This is used to acquire the indent at the specified index. If
* the indent does not exist at the specified index then on is
* created using the current value of the indent. The very first
* indent taken from this will be an empty string value.
*
* @param index this is the index to acquire the indent from
*
* @return this returns the indent from the specified index
*/
private String indent(int index) {
if(indent > 0) {
String text = cache.get(index);
if(text == null){
text = create();
cache.set(index, text);
}
if(cache.size() >0) {
return text;
}
}
return "";
}
/**
* This is used to create an indent which can later be pushed on
* to the stack. If the number of spaces to be added is zero then
* this will return a single character string with a line feed.
*
* @return this will create an indent to be added to the stack
*/
private String create() {
char[] text = new char[count+1];
if(count > 0) {
text[0] = '\n';
for(int i = 1; i <= count; i++){
text[i] = ' ';
}
return new String(text);
}
return "\n";
}
/**
* The Cache
object is used create an indexable list
* which allows the indenter to quickly acquire an indent using
* a stack position. This ensures that the indenter need only
* create an index once for a given stack position. The number of
* indents held within this cache can also be tracked.
*/
private static class Cache {
/**
* This is used to track indent strings within the cache.
*/
private String[] list;
/**
* Represents the number of indent strings held by the cache.
*/
private int count;
/**
* Constructor for the Cache
object. This creates
* a cache of the specified size, the specified size acts as
* an initial size and the cache can be expanded on demand.
*
* @param size the initial number of entries in the cache
*/
public Cache(int size) {
this.list = new String[size];
}
/**
* This method is used to retrieve the number of indents that
* have been added to the cache. This is used to determine if
* an indent request is the first.
*
* @return this returns the number of indents in the cache
*/
public int size() {
return count;
}
/**
* This method is used to add the specified indent on to the
* cache. The index allows the cache to act as a stack, when
* the index is specified it can be used to retrieve the same
* indent using that index.
*
* @param index this is the position to add the index to
* @param text this is the indent to add to the position
*/
public void set(int index, String text) {
if(index >= list.length) {
resize(index * 2);
}
if(index > count) {
count = index;
}
list[index] = text;
}
/**
* This method is used to retrieve an indent from the given
* position. This allows the indenter to use the cache as a
* stack, by increasing and decreasing the index as required.
*
* @param index the position to retrieve the indent from
*
* @return this is the indent retrieve from the given index
*/
public String get(int index) {
if(index < list.length) {
return list[index];
}
return null;
}
/**
* Should the number of indents to be cache grows larger than
* the default initial size then this will increase the size
* of the cache. This ensures that the indenter can handle an
* arbitrary number of indents for a given output.
*
* @param size this is the size to expand the cache to
*/
private void resize(int size) {
String[] temp = new String[size];
for(int i = 0; i < list.length; i++){
temp[i] = list[i];
}
list = temp;
}
}
}