Hi,

I was trying to solve the problem of making empty tags be rendered as closed start tags (i.e., <foo/> instead of <foo></foo>) for structures, and ended up with a neat writer which solves the problem genericly. Simply attach the writer to a MarshallngContext and you're off.

Since I'm overriding methods (in the inheritance chain) based on UTF8StreamWriter, I guess that it would be better if a "closed" empty tag writer was included in jibx...

I'm sharing the solution here in case someone finds it useful :)


Thanks,
Ørjan
package com.colibria.ccc.xml;

import org.jibx.runtime.impl.UTF8StreamWriter;

import java.io.IOException;

/**
 * An UTF-8 XML writer which writes empty structures/mappings as a single tag.
 * <p/>
 * E.g., instead of <code>&lt;foo&gt;&lt;/foo&gt;</code> the single tag &lt;foo/&gt; is written.
 * <p/>
 * <code>$Id: EmptyTagClosedUTF8StreamWriter.java,v 1.1 2006/02/27 09:45:36 austvold Exp $</code>
 *
 * @author &Oslash;rjan Nygaard Austvold
 * @version $Revision: 1.1 $
 */
class EmptyTagClosedUTF8StreamWriter extends UTF8StreamWriter {
    /** True if a pending close is waiting, false otherwise. */
    boolean pendingClose = false;

    public EmptyTagClosedUTF8StreamWriter(String[] uris) {
        super(uris);
    }

    public EmptyTagClosedUTF8StreamWriter(EmptyTagClosedUTF8StreamWriter base, String[] uris) {
        super(base, uris);
    }

    public void startTagOpen(int index, String name) throws IOException {
        // write pending close of previous tag, if any
        writePendingCloseStartTagIfNeeded();
        super.startTagOpen(index, name);
    }

    public void closeStartTag() throws IOException {
        // do not close tag now -- wait to see if content or text arrives
        pendingClose = true;
        incrementNesting();
        m_textSeen = m_contentSeen = false;
    }

    public void closeEmptyTag() throws IOException {
        pendingClose = false;
        super.closeEmptyTag();
    }

    public void startTagClosed(int index, String name) throws IOException {
        // write pending close of previous tag, if any
        writePendingCloseStartTagIfNeeded();

        // write tag as open but do nesting increment
        indent();
        writeMarkup('<');
        writePrefix(index);
        writeMarkup(name);
        incrementNesting();
        m_textSeen = m_contentSeen = false;
        pendingClose = true;
    }

    public void endTag(int index, String name) throws IOException {
        if (pendingClose) {
            // replace end tag with end of start tag
            writeMarkup("/>");
            pendingClose = false;
        } else {
            // write normal end tag
            if (m_contentSeen && !m_textSeen) {
                indent(-1);
            }
            writeMarkup("</");
            writePrefix(index);
            writeMarkup(name);
            writeMarkup('>');
        }
        decrementNesting();
        m_textSeen = false;
        m_contentSeen = true;
    }

    public void writeComment(String text) throws IOException {
        // write pending close of previous tag, if any
        writePendingCloseStartTagIfNeeded();
        super.writeComment(text);
    }

    public void writeEntityRef(String name) throws IOException {
        // write pending close of previous tag, if any
        writePendingCloseStartTagIfNeeded();
        super.writeEntityRef(name);
    }

    public void writePI(String target, String data) throws IOException {
        // write pending close of previous tag, if any
        writePendingCloseStartTagIfNeeded();
        super.writePI(target, data);
    }

    public void reset() {
        // reset pending tag close state
        pendingClose = false;
        super.reset();
    }

    public void writeTextContent(String text) throws IOException {
        if (text.length() > 0) {
            // write pending close of previous tag, if any
            writePendingCloseStartTagIfNeeded();
            super.writeTextContent(text);
        }
    }

    public void writeCData(String text) throws IOException {
        if (text.length() > 0) {
            // write pending close of previous tag, if any
            writePendingCloseStartTagIfNeeded();
            super.writeTextContent(text);
        }
    }

    /**
     * Writes a pending close of tag as a normal tag close.
     * @throws java.io.IOException on error writing to document
     */
    private void writePendingCloseStartTagIfNeeded() throws IOException {
        if (pendingClose) {
            super.writeMarkup(">");
            pendingClose = false;
        }
    }
}

Reply via email to