com.thaiopensource.xml.out.XmlWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of trang Show documentation
Show all versions of trang Show documentation
Trang, a multi-format schema converter based on RELAX NG.
package com.thaiopensource.xml.out;
import java.io.Writer;
import java.io.IOException;
import java.io.CharConversionException;
import com.thaiopensource.util.Utf16;
public class XmlWriter {
static final private String indentString = " ";
private final Writer writer;
private final CharRepertoire cr;
private static final int OTHER = 0; // must be at beginning of line
private static final int IN_START_TAG = 1;
private static final int AFTER_DATA = 2;
private int state = OTHER;
private String[] stack = new String[20];
private int level = 0;
private String newline = "\n";
public XmlWriter(Writer writer, CharRepertoire cr) {
this.writer = writer;
this.cr = cr;
}
public void setNewline(String newline) {
this.newline = newline;
}
public void close() throws IOException {
writer.close();
}
public void flush() throws IOException {
writer.flush();
}
public void writeXmlDecl(String enc) throws IOException {
writer.write("");
writer.write(newline);
}
public void startElement(String name) throws IOException {
switch (state) {
case IN_START_TAG:
writer.write('>');
writer.write(newline);
indent();
break;
case OTHER:
indent();
// fall through
case AFTER_DATA:
state = IN_START_TAG;
break;
}
writer.write('<');
outputMarkup(name);
push(name);
}
public void endElement() throws IOException {
String name = pop();
switch (state) {
case IN_START_TAG:
writer.write("/>");
break;
case OTHER:
indent();
// fall through
case AFTER_DATA:
writer.write("");
outputMarkup(name);
writer.write('>');
break;
}
writer.write(newline);
state = OTHER;
}
public void attribute(String name, String value) throws IOException {
if (state != IN_START_TAG)
throw new IllegalStateException();
writer.write(' ');
outputMarkup(name);
writer.write('=');
writer.write('"');
outputData(value, true, false);
writer.write('"');
}
public void characters(String str) throws IOException {
characters(str, false);
}
public void characters(String str, boolean useCharRef) throws IOException {
if (state == IN_START_TAG)
writer.write('>');
state = AFTER_DATA;
outputData(str, false, useCharRef);
}
public void comment(String str) throws IOException {
if (state == IN_START_TAG) {
writer.write('>');
state = OTHER;
writer.write(newline);
}
writer.write("");
if (state != AFTER_DATA)
writer.write(newline);
}
public void processingInstruction(String target, String str) throws IOException {
if (state == IN_START_TAG) {
writer.write('>');
state = OTHER;
writer.write(newline);
}
writer.write("");
outputMarkup(target);
if (str.length() != 0) {
writer.write(' ');
outputMarkup(str);
}
writer.write("?>");
if (state != AFTER_DATA)
writer.write(newline);
}
private void outputMarkup(String str) throws IOException {
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
if (Utf16.isSurrogate1(c)) {
if (i == len || !Utf16.isSurrogate2(str.charAt(i)))
throw new CharConversionException("surrogate pair integrity failure");
if (!cr.contains(c, str.charAt(i)))
throw new CharConversionException();
}
else if (!cr.contains(c))
throw new CharConversionException();
}
outputLines(str);
}
private void outputLines(String str) throws IOException {
while (str.length() > 0) {
int i = str.indexOf('\n');
if (i < 0) {
writer.write(str);
break;
}
if (i > 0)
writer.write(str.substring(0, i));
writer.write(newline);
str = str.substring(i + 1);
}
}
private void outputData(String str, boolean inAttribute, boolean useCharRef)
throws IOException {
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
switch (c) {
case '<':
writer.write("<");
break;
case '>':
writer.write(">");
break;
case '&':
writer.write("&");
break;
case '"':
writer.write(""");
break;
case '\r':
writer.write("
");
break;
case '\t':
if (inAttribute)
writer.write(" ");
else
writer.write('\t');
break;
case '\n':
if (inAttribute)
writer.write("
");
else
writer.write(newline);
break;
default:
if (Utf16.isSurrogate1(c)) {
++i;
if (i < len) {
char c2 = str.charAt(i);
if (Utf16.isSurrogate2(c)) {
charRef(Utf16.scalarValue(c, c2));
break;
}
}
throw new CharConversionException("surrogate pair integrity failure");
}
if (cr.contains(c) && !useCharRef)
writer.write(c);
else
charRef(c);
break;
}
}
}
private void charRef(int c) throws IOException {
writer.write("");
int nDigits = c > 0xFFFF ? 6 : 4;
for (int i = 0; i < nDigits; i++)
writer.write("0123456789ABCDEF".charAt((c >> (4*(nDigits - 1 - i)))
& 0xF));
writer.write(";");
}
private void indent() throws IOException {
for (int i = 0; i < level; i++)
writer.write(indentString);
}
private final void push(String name) {
if (level == stack.length) {
String[] tem = stack;
stack = new String[stack.length * 2];
System.arraycopy(tem, 0, stack, 0, tem.length);
}
stack[level++] = name;
}
private final String pop() {
return stack[--level];
}
}