Created
October 15, 2011 15:45
-
-
Save qbg/1289728 to your computer and use it in GitHub Desktop.
DOM style streaming XML gist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The entire library is contained in the class XMLWriter. | |
== USAGE == | |
Say we wanted to produce the following XML: | |
======== | |
<?xml version="1.0" encoding="UTF-8"?> | |
<compiler-settings> | |
<speed>3</speed> | |
<safety>0</safety> | |
<debug foo="bar">0</debug> | |
<parent> | |
<child>42</child> | |
Lots of text | |
</parent> | |
</compiler-settings> | |
======== | |
We can write the above XML to a path/File/OutputStream out with the following code: | |
======== | |
XMLWriter compiler = new XMLWriter(out, "compiler-settings"); | |
compiler.addSimpleElement("speed", "3"); | |
compiler.addSimpleElement("safety", "0"); | |
XMLWriter debug = compiler.addElement("debug"); | |
debug.addAttribute("foo", "bar"); | |
debug.addInlineText("0"); | |
XMLWriter parent = compiler.addElement("parent"); | |
parent.addSimpleElement("child", "42"); | |
parent.addText("Lots of text"); | |
compiler.close(); | |
======== | |
For my purposes, I've only needed the above features so far. | |
== Sample implementation == | |
import java.io.Closeable; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.io.OutputStreamWriter; | |
import java.io.UnsupportedEncodingException; | |
import java.io.Writer; | |
public class XMLWriter implements Closeable { | |
private static final String EOL = "\r\n"; | |
private static final String INDENT = " "; | |
private Writer writer; | |
private boolean hasHeader = false; | |
private boolean isInline = true; | |
private XMLWriter lastChild = null; | |
private String name; | |
private int level; | |
private XMLWriter(String name, XMLWriter parent) { | |
this.writer = parent.writer; | |
this.name = name; | |
this.level = parent.level + 1; | |
writeStart(); | |
} | |
private void createWriter(Writer writer, String name, String encoding) { | |
this.writer = writer; | |
this.name = name; | |
this.level = 0; | |
write("<?xml version=\"1.0\" encoding=\""); | |
write(encoding); | |
write("\"?>"); | |
writeStart(); | |
} | |
public XMLWriter(Writer writer, String name, String encoding) { | |
createWriter(writer, name, encoding); | |
} | |
private void createWriter(OutputStream os, String name) { | |
try { | |
createWriter(new OutputStreamWriter(os, "UTF-8"), name, "UTF-8"); | |
} catch (UnsupportedEncodingException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public XMLWriter(OutputStream os, String name) { | |
createWriter(os, name); | |
} | |
public XMLWriter(File file, String name) { | |
try { | |
OutputStream os = new FileOutputStream(file); | |
createWriter(os, name); | |
} catch (FileNotFoundException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public XMLWriter(String path, String name) { | |
try { | |
OutputStream os = new FileOutputStream(path); | |
createWriter(os, name); | |
} catch (FileNotFoundException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private void write(String text) { | |
try { | |
writer.write(text); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private void writeEscape(String text) { | |
try { | |
for (int i = 0; i < text.length(); i++) { | |
char c = text.charAt(i); | |
switch (c) { | |
case '<': | |
writer.write("<"); | |
break; | |
case '>': | |
writer.write(">"); | |
break; | |
case '&': | |
writer.write("&"); | |
break; | |
case '"': | |
writer.write("""); | |
break; | |
default: | |
writer.write(c); | |
break; | |
} | |
} | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private void writeStart() { | |
write(EOL); | |
indent(level); | |
write("<"); | |
write(name); | |
} | |
private void indent(int n) { | |
for (int i = 0; i < n; i++) { | |
write(INDENT); | |
} | |
} | |
public void flush() { | |
try { | |
writer.flush(); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
@Override | |
public void close() { | |
try { | |
finish(); | |
write(EOL); | |
writer.close(); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private void writeHeader() { | |
if (!hasHeader) { | |
write(">"); | |
hasHeader = true; | |
} | |
} | |
private void writeFinish() { | |
writeHeader(); | |
if (lastChild != null) { | |
lastChild.finish(); | |
lastChild = null; | |
} | |
} | |
private void finish() { | |
if (!hasHeader) { | |
write(" />"); | |
} else { | |
writeFinish(); | |
if (!isInline) { | |
write(EOL); | |
indent(level); | |
} | |
write("</"); | |
write(name); | |
write(">"); | |
} | |
} | |
public void addAttribute(String attr, String value) { | |
write(" "); | |
write(attr); | |
write("=\""); | |
writeEscape(value); | |
write("\""); | |
} | |
public XMLWriter addElement(String name) { | |
writeFinish(); | |
isInline = false; | |
lastChild = new XMLWriter(name, this); | |
return lastChild; | |
} | |
public void addText(String text) { | |
writeFinish(); | |
isInline = false; | |
write(EOL); | |
indent(level + 1); | |
writeEscape(text); | |
} | |
public void addInlineText(String text) { | |
writeFinish(); | |
writeEscape(text); | |
} | |
public void addSimpleElement(String name, String value) { | |
XMLWriter element = addElement(name); | |
element.addInlineText(value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment