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

org.xs4j.xmlspitter.InternalStream Maven / Gradle / Ivy

Go to download

An attempt to port parsing capabilities offered by Groovy XMLSlurper into the Java world. The following is not planned to be accurate projection, instead the most useful functions will be implemented.

The newest version!
package org.xs4j.xmlspitter;

import org.xs4j.XMLNode;
import org.xs4j.util.NotNull;
import org.xs4j.util.Nullable;

import javax.xml.XMLConstants;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;

import static org.xs4j.util.NonNullValidator.requireNonNull;

/**
 * Created by mturski on 1/3/2017.
 */
public class InternalStream implements XMLStream {
    private static final String NO_START_FOR_END_ELEMENT_EXCEPTION = "No element was found to write";

    private static final String START_DOCUMENT_PATTERN = "";

    private static final char TAG_OPENING_CHAR = '<';
    private static final String END_TAG_OPENING_CHAR = "";
    private static final char TAG_CLOSING_CHAR = '>';
    private static final char ATTR_LEADING_SPACE = ' ';
    private static final String ATTR_EQUALS_AND_QUOTE = "=\"";
    private static final String ATTR_CLOSING_QUOTE = "\"";
    private static final String DEFAULT_NAMESPACE = ATTR_LEADING_SPACE + XMLConstants.XMLNS_ATTRIBUTE + ATTR_EQUALS_AND_QUOTE;

    private final long id;
    private final Writer writer;

    private final Deque descendants = new ArrayDeque();

    private int defaultNamespaceAtDepth = Integer.MAX_VALUE;

    InternalStream(long id, Writer writer) {
        this.id = id;
        this.writer = writer;
    }

    InternalStream(long id, OutputStream outputStream) {
        this(id, new OutputStreamWriter(outputStream));
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public void writeStartDocument() {
        doWriteStartDocument(XMLSpitterFactory.DEFAULT_XML_DOCUMENT_ENCODING, XMLSpitterFactory.DEFAULT_XML_DOCUMENT_VERSION);
    }


    @Override
    public void writeStartDocument(@NotNull String encoding) {
        doWriteStartDocument(encoding, XMLSpitterFactory.DEFAULT_XML_DOCUMENT_VERSION);
    }

    @Override
    public void writeStartDocument(@NotNull String encoding, @NotNull String version) {
        doWriteStartDocument(encoding, version);
    }

    private void doWriteStartDocument(String encoding, String version) {
        doWrite(String.format(START_DOCUMENT_PATTERN, version, encoding));
    }

    @Override
    public void writeStartElement(@NotNull XMLNode node) {
        requireNonNull(node);

        doWrite(TAG_OPENING_CHAR + node.getQName() + doWriteDefaultNamespaceAttribute(node));
        doWrite(doWriteAttributes(node.getAttributes()) + TAG_CLOSING_CHAR);
        descendants.addLast(node);
    }

    @Override
    public void writeElement(@NotNull XMLNode node) {
        requireNonNull(node);

        if (node.getText() == null) {
            doWrite(TAG_OPENING_CHAR + node.getQName() + doWriteDefaultNamespaceAttribute(node));
            doWrite(doWriteAttributes(node.getAttributes()) + EMPTY_ELEMENT_TAG_CLOSING_CHARS);
        } else {
            writeStartElement(node);
            writeCharacters(node.getText());
            writeEndElement();
        }
    }

    private String doWriteDefaultNamespaceAttribute(XMLNode node) {
        if (node.getDepth() <= defaultNamespaceAtDepth) {
            if (node.getPrefix() == null && node.getNamespace() != null) {
                defaultNamespaceAtDepth = node.getDepth();

                return DEFAULT_NAMESPACE + node.getNamespace() + ATTR_CLOSING_QUOTE;
            } else
                defaultNamespaceAtDepth = Integer.MAX_VALUE;
        }

        return "";
    }

    private String doWriteAttributes(Map attributeByQName) {
        String result = "";

        for (String qName : attributeByQName.keySet())
            result += ATTR_LEADING_SPACE + qName + ATTR_EQUALS_AND_QUOTE + attributeByQName.get(qName) + ATTR_CLOSING_QUOTE;

        return result;
    }

    @Override
    public void writeCharacters(@Nullable String characters) {
        if (characters != null)
            doWrite(characters);
    }

    @Override
    public void writeCharacters(@NotNull char[] characters) {
        requireNonNull((Object)characters);

        doWrite(characters);
    }

    @Override
    public void writeCharacters(@NotNull char[] characters, int startPos, int length) {
        requireNonNull((Object)characters);

        doWrite(characters, startPos, length);
    }

    @Override
    public void writeCharacters(@NotNull XMLNode node) {
        requireNonNull(node);

        String text = node.getText();
        if (text != null)
            doWrite(text);
    }

    @Override
    public void writeEndElement() {
        XMLNode node = descendants.removeLast();
        if (node == null)
            throw new XMLStreamRuntimeException(NO_START_FOR_END_ELEMENT_EXCEPTION);

        doWrite(END_TAG_OPENING_CHAR + node.getQName() + TAG_CLOSING_CHAR);
    }

    @Override
    public void writeEndElement(@NotNull XMLNode node) {
        requireNonNull(node);
        descendants.removeLastOccurrence(node);

        doWrite(END_TAG_OPENING_CHAR + node.getQName() + TAG_CLOSING_CHAR);
    }

    @Override
    public void flush() {
        doFlush();
    }


    @Override
    public void close() {
        doClose();
    }

    @Override
    public final boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof XMLStream)) return false;

        XMLStream that = (XMLStream) o;

        return id == that.getId();
    }

    @Override
    public int hashCode() {
        return (int) (id ^ (id >>> 32));
    }

    private void doWrite(String text) {
        try {
            writer.write(text);
        } catch (IOException e) {
            throw new XMLStreamRuntimeException(e);
        }
    }

    private void doWrite(char[] text) {
        try {
            writer.write(text);
        } catch (IOException e) {
            throw new XMLStreamRuntimeException(e);
        }
    }

    private void doWrite(char[] text, int startPosition, int length) {
        try {
            writer.write(text, startPosition, length);
        } catch (IOException e) {
            throw new XMLStreamRuntimeException(e);
        }
    }

    private void doFlush() {
        try {
            writer.flush();
        } catch (IOException e) {
            throw new XMLStreamRuntimeException(e);
        }
    }

    private void doClose() {
        try {
            writer.close();
        } catch (IOException e) {
            throw new XMLStreamRuntimeException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy