All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.utils.format.XmlPrettyPrinter Maven / Gradle / Ivy

There is a newer version: 3.5.0
Show newest version
package fi.evolver.utils.format;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import fi.evolver.utils.parse.CharStream;

public class XmlPrettyPrinter {
	public static final XmlPrettyPrinter INSTANT = new XmlPrettyPrinter("  ");


    private enum State {
        TEXT,
        START_TAG,
        END_TAG,
        ATTRIBUTE,
        CONTENT_START,
        ;

        public boolean is(State... states) {
            for (State s: states) {
                if (s == this)
                    return true;
            }
            return false;
        }
    }


    private final String indentString;

    public XmlPrettyPrinter(String indentString) {
        this.indentString = indentString;
    }


    public static String format(String xml) {
        StringReader reader = new StringReader(xml);
        xml = null;
        StringWriter writer = new StringWriter();
        try {
            new XmlPrettyPrinter("\t").format(reader, writer);
            return writer.toString();
        } catch (IOException e) {
            return "";
        }
    }


    public void format(Reader input, Writer output) throws IOException {
        format(new CharStream(input, 4), output, 0, false);
    }

    public void format(CharStream stream, Writer output, int baseIndentation, boolean inComment) throws IOException {
        int indentation = baseIndentation;

        State state = State.TEXT;
        if (stream.accept('<', '?')) {
            state = State.START_TAG;
            output.write("");
                if (xml) {
                    containsXml = true;
                    while (stream.acceptWhitespace()) { /* skip */ }
                    if (!stream.has('<'))
                        indent(output, indentation);
                }
            }
            else if (stream.accept('-', '-', '>')) {
                if (inComment)
                    return;
                else
                    output.append("-->");
            }
            else if (state.is(State.TEXT, State.CONTENT_START) && stream.accept('<', '/')) {
                --indentation;
                if (containsXml)
                    indent(output, indentation);
                state = State.END_TAG;
                debug(output, "[END]");
                output.append("')) {
                debug(output, "[CONTENT]");
                output.append("/>");
                --indentation;
                state = State.CONTENT_START;
                containsXml = true;
            }
            else if (state.is(State.START_TAG, State.END_TAG) && stream.accept('>')) {
                output.append('>');
                debug(output, "[CONTENT]");
                containsXml = state.is(State.END_TAG);
                state = State.CONTENT_START;
            }
            else if (state.is(State.START_TAG, State.END_TAG) && stream.accept('"')) {
                debug(output, "[ATTRIBUTE]");
                state = State.ATTRIBUTE;
                output.append('"');
            }
            else if (state.is(State.ATTRIBUTE) && stream.accept('"')) {
                state = State.START_TAG;
                output.append('"');
                debug(output, "[START]");
            }
            else {
                if (state.is(State.CONTENT_START)) {
                    debug(output, "[TEXT]");
                    state = State.TEXT;
                }
                char c = stream.next();
                if (state.is(State.TEXT) && Character.isWhitespace(c))
                    whitespace.append(c);
                else {
                    flushWhitespace(output, whitespace);
                    output.append(c);
                }
            }

            if (!state.is(State.TEXT))
                whitespace.setLength(0);
        }

        output.append('\n');
    }


    private static void flushWhitespace(Writer output, StringBuilder whitespace) throws IOException {
        if (whitespace.length() > 0) {
            output.append(whitespace);
            whitespace.setLength(0);
        }
    }


    private void indent(Writer writer, int amount) throws IOException {
        writer.append('\n');
        for (int i = 0; i < amount; ++i)
            writer.append(indentString);
    }


    @SuppressWarnings("unused")
    private void debug(Writer output, String text) throws IOException {
        //output.append(text);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy