1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/*******************************************************************************
2b9d1b54e300318b470d9fedccc69d75187016444Evgeny Mandrikov * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials
4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0
5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at
6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html
7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors:
9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *    Marc R. Hoffmann - initial API and implementation
10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/
12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.report.internal.xml;
13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport static java.lang.String.format;
15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.IOException;
17e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.Writer;
18e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
19e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/**
20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Simple API to create well formed XML streams. A {@link XMLElement} instance
21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * represents a single element in a XML document.
22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @see XMLDocument
24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */
25e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class XMLElement {
26e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
27e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char SPACE = ' ';
28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
29e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char EQ = '=';
30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char LT = '<';
32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char GT = '>';
34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char QUOT = '"';
36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char AMP = '&';
38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private static final char SLASH = '/';
40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Writer for content output */
42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected final Writer writer;
43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private final String name;
45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private boolean openTagDone;
47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private boolean closed;
49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private XMLElement lastchild;
51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Creates a new element for a XML document.
54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param writer
56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            all output will be written directly to this
57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param name
58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            element name
59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected XMLElement(final Writer writer, final String name) {
61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.writer = writer;
62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.name = name;
63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.openTagDone = false;
64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.closed = false;
65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.lastchild = null;
66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Emits the beginning of the open tag. This method has to be called before
70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * other other methods are called on this element.
71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
75e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected void beginOpenTag() throws IOException {
76e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(LT);
77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(name);
78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private void finishOpenTag() throws IOException {
81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (!openTagDone) {
82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			writer.append(GT);
83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			openTagDone = true;
84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
87e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
88e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Adds the given child to this element. This will close all previous child
89e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * elements.
90e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
91e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param child
92e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            child element to add
93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of invalid nesting or problems with the writer
95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
96e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected void addChildElement(final XMLElement child) throws IOException {
97e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (closed) {
98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new IOException(format("Element %s already closed.", name));
99e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		finishOpenTag();
101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (lastchild != null) {
102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			lastchild.close();
103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		child.beginOpenTag();
105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		lastchild = child;
106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private void quote(final String text) throws IOException {
109e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final int len = text.length();
110e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		for (int i = 0; i < len; i++) {
111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			final char c = text.charAt(i);
112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			switch (c) {
113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			case LT:
114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write("&lt;");
115e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				break;
116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			case GT:
117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write("&gt;");
118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				break;
119e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			case QUOT:
120e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write("&quot;");
121e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				break;
122e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			case AMP:
123e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write("&amp;");
124e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				break;
125e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			default:
126e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write(c);
127e35a34adcc3a47eac6723533e811e52c288d4dd5Mirko Friedenhagen				break;
128e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
129e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
130e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
131e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
132e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
133e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Adds an attribute to this element. May only be called before an child
134e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * element is added or this element has been closed. The attribute value
135e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * will be quoted. If the value is <code>null</code> the attribute will not
136e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * be added.
137e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
138e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param name
139e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute name
140e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param value
141e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute value or <code>null</code>
142e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
143e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return this element
144e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
145e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
146e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
147e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public XMLElement attr(final String name, final String value)
148e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throws IOException {
149e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (value == null) {
150e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			return this;
151e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
152e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (closed || openTagDone) {
153e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new IOException(format("Element %s already closed.",
154e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov					this.name));
155e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
156e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(SPACE);
157e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(name);
158e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(EQ);
159e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(QUOT);
160e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		quote(value);
161e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writer.write(QUOT);
162e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return this;
163e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
164e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
165e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
166e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Adds an attribute to this element. May only be called before an child
167e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * element is added or this element has been closed. The attribute value is
168e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * the decimal representation of the given int value.
169e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
170e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param name
171e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute name
172e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param value
173e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute value
174e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
175e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return this element
176e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
177e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
178e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
179e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public XMLElement attr(final String name, final int value)
180e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throws IOException {
181e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return attr(name, String.valueOf(value));
182e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
183e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
184e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
185e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Adds an attribute to this element. May only be called before an child
186e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * element is added or this element has been closed. The attribute value is
187e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * the decimal representation of the given long value.
188e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
189e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param name
190e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute name
191e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param value
192e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            attribute value
193e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
194e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return this element
195e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
196e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
197e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
198e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public XMLElement attr(final String name, final long value)
199e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throws IOException {
200e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return attr(name, String.valueOf(value));
201e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
202e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
203e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
204e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Adds the given text as a child to this node. The text will be quoted.
205e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
206e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param text
207e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            text to add
208e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return this element
209e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
210e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
211e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
212e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public XMLElement text(final String text) throws IOException {
213e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (closed) {
214e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new IOException(format("Element %s already closed.", name));
215e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
216e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		finishOpenTag();
217e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (lastchild != null) {
218e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			lastchild.close();
219e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
220e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		quote(text);
221e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return this;
222e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
223e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
224e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
225e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Creates a new child element for this element,
226e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
227e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param name
228e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            name of the child element
229e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return child element instance
230e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
231e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
232e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
233e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public XMLElement element(final String name) throws IOException {
234e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final XMLElement element = new XMLElement(writer, name);
235e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		addChildElement(element);
236e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return element;
237e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
238e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
239e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
240e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Closes this element if it has not been closed before.
241e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
242e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
243e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             in case of problems with the writer
244e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
245e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void close() throws IOException {
246e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (!closed) {
247e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			if (lastchild != null) {
248e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				lastchild.close();
249e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
250e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			if (openTagDone) {
251e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write(LT);
252e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write(SLASH);
253e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write(name);
254e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			} else {
255e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				writer.write(SLASH);
256e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
257e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			writer.write(GT);
258e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			closed = true;
259e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			openTagDone = true;
260e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
261e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
262e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
263e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov}
264