Skip to content

Instantly share code, notes, and snippets.

@fumokmm
Created September 17, 2011 01:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fumokmm/1223474 to your computer and use it in GitHub Desktop.
Save fumokmm/1223474 to your computer and use it in GitHub Desktop.
Make Groovy's MarkupBuilder style DSL String
// http://d.hatena.ne.jp/fumokmm/20110917/1316223642
import org.xml.sax.helpers.DefaultHandler
import org.xml.sax.Attributes
class GroovyMarkupDSLHandler extends DefaultHandler {
IndentPrinter p
boolean needNewLine
GroovyMarkupDSLHandler(Writer writer = new PrintWriter(System.out), String indent = ' ') {
p = new IndentPrinter(writer, indent)
needNewLine = false
}
def toAttrMap = { Attributes attr ->
attr.length ? (0..<attr.length).collectEntries{
[attr.getQName(it), attr.getValue(it)]
} : null
}
def toMethodCall = { Map attrMap ->
attrMap.collect{ "${it.key}: '${it.value}'" }.join(', ')
}
def printNewLineIfNeed() {if (needNewLine) {p.println ''; needNewLine = false}}
@Override void startDocument() {
//println "GroovyMarkupDSLHandler START."
}
@Override void endDocument() {
p.flush()
//println "GroovyMarkupDSLHandler END."
}
@Override void startElement(String ns, String localName, String qName, Attributes atts) {
printNewLineIfNeed()
p.printIndent()
def attr = toAttrMap(atts)
if (attr) {
p.println "$qName(${toMethodCall(attr)}) {"
} else {
p.println "$qName {"
}
p.incrementIndent()
}
@Override void endElement(String ns, String localName, String qName) {
printNewLineIfNeed()
p.decrementIndent()
p.printIndent()
p.print '}'
needNewLine = true
}
@Override void characters(char[] chars, int offset, int length) {
printNewLineIfNeed()
def str = chars[offset..<offset+length].join().trim()
if(str) {
p.printIndent()
p.println "mkp.yield('${str}')"
}
}
}
import javax.xml.parsers.SAXParserFactory
import org.xml.sax.helpers.DefaultHandler
import org.xml.sax.InputSource
import groovy.xml.MarkupBuilder
def getDSLString(File xml, Writer w, String indent = ' ') {
def handler = new GroovyMarkupDSLHandler(w, indent)
def reader = SAXParserFactory.newInstance().newSAXParser().xmlReader
reader.contentHandler = handler
reader.parse(new InputSource(xml.newInputStream()))
}
def s1 = new StringWriter()
getDSLString(new File('test1.xml'), s1)
def expected1 = '''\
root {
a {
b {
c {
}
}
}
}'''
assert expected1 == s1.toString()
// 逆変換(一旦DSLにしたものをMarkupした結果のXMLと元のXMLを比較)
assert new File('test1.xml').text == Eval.me("""
def sw = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(sw)
xml.doubleQuotes = true
xml.${s1.toString()}
sw.toString()
""")
def s2 = new StringWriter()
getDSLString(new File('test2.xml'), s2, ' '*4) // タブ=スペース*4
def expected2 = '''\
root {
a(hoge: 'val1', fuga: 'val2') {
}
b {
}
c(hoge: 'val3') {
d {
mkp.yield('val4')
}
e {
f(hoge: 'val5') {
mkp.yield('ばりゅー6')
}
}
}
}'''
assert expected2 == s2.toString()
// 逆変換(一旦DSLにしたものをMarkupした結果のXMLと元のXMLを比較)
assert new File('test2.xml').text == Eval.me("""
def sw = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(sw)
xml.doubleQuotes = true
xml.${s2.toString()}
sw.toString()
""")
<root>
<a>
<b>
<c />
</b>
</a>
</root>
<root>
<a hoge="val1" fuga="val2" />
<b />
<c hoge="val3">
<d>val4</d>
<e>
<f hoge="val5">ばりゅー6</f>
</e>
</c>
</root>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment