/******************************************************************************* * Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://robocode.sourceforge.net/license/epl-v10.html * * Contributors: * Pavel Savara * - Initial implementation *******************************************************************************/ package net.sf.robocode.serialization; import java.io.IOException; import java.io.Writer; import java.text.CharacterIterator; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.StringCharacterIterator; import java.util.Locale; import java.util.Stack; /** * @author Pavel Savara (original) */ public class XmlWriter { private static final DecimalFormat decimalFormat = new DecimalFormat("#.####", new DecimalFormatSymbols(Locale.US)); final Writer writer; final Stack<String> elements = new Stack<String>(); boolean headClosed = true; boolean innerElement = false; boolean indent = true; public XmlWriter(Writer writer, boolean indent) { this.writer = writer; this.indent = indent; } public void startDocument() throws IOException { writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); } public void startElement(String name) throws IOException { closeHead(); indent(elements.size()); elements.push(name); writer.write('<'); writer.write(encode(name)); headClosed = false; innerElement = false; } public void writeAttribute(String name, String value) throws IOException { if (value != null) { writer.write(' '); writer.write(encode(name)); writer.write("=\""); writer.write(encode(value)); writer.write('"'); } } public void writeAttribute(String name, boolean value) throws IOException { writeAttribute(name, Boolean.toString(value)); } public void writeAttribute(String name, long value) throws IOException { writeAttribute(name, Long.toString(value)); } public void writeAttribute(String name, double value, boolean trim) throws IOException { if (trim) { writeAttribute(name, decimalFormat.format(value)); } else { writeAttribute(name, Double.toString(value)); } } public void endElement() throws IOException { String name = elements.pop(); if (innerElement || headClosed) { closeHead(); indent(elements.size()); writer.write("</"); writer.write(encode(name)); writer.write(">"); } else { writer.write("/>"); headClosed = true; } newline(); innerElement = true; } private void newline() throws IOException { if (indent) { writer.write("\n"); } } private void closeHead() throws IOException { if (!headClosed) { writer.write('>'); newline(); headClosed = true; } } private void indent(int level) throws IOException { if (indent) { for (int i = 0; i < level; i++) { writer.write("\t"); } } } public static String encode(String text) { final StringBuilder result = new StringBuilder(); final StringCharacterIterator iterator = new StringCharacterIterator(text); char character = iterator.current(); while (character != CharacterIterator.DONE) { if (character == '<') { result.append("<"); } else if (character == '>') { result.append(">"); } else if (character == '&') { result.append("&"); } else if (character == '\"') { result.append("""); } else if (character == '\n') { result.append(" "); } else { // the char is not a special one // add it to the result as is result.append(character); } character = iterator.next(); } return result.toString(); } }