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><foo></foo></code> the single tag <foo/> is written.
* <p/>
* <code>$Id: EmptyTagClosedUTF8StreamWriter.java,v 1.1 2006/02/27 09:45:36 austvold Exp $</code>
*
* @author Ø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;
}
}
}