Groovy 把使用 XML 的美妙和简易性推向了极致,这就是 GroovyMarkup,它不仅简化了 SAX、DOM 操作,并且把这一理念引入到了 Swing、Swt 界面绘制领域中,Ant、Maven 构建脚本生成中;甚至铺散到更广阔的领域。
- groovy.xml.MarkupBuilder -- 将你的对象序列化成 XML 或 XHTML
- groovy.xml.SAXBuilder -- 可以用于现有的 SAX 处理器
- groovy.xml.DOMBuilder -- 创建并解析 DOM 文档
- groovy.util.AntBuilder -- 用来创建 Ant 构建文件
- groovy.swing.SwingBuilder -- 用来创建 Swing 用户界面
- groovy.util.NodeBuilder -- 创建一般的任意对象的树状结构
构建xml
def sw = new StringWriter();
def xml = new groovy.xml.MarkupBuilder(sw)
xml.langs(type:"current"){
language(version:"1.6", flavor:"static", "java")
language(version:"1.7", "groovy")
language(version:"4", "javascript")
}
println sw
生成内容如下:
<langs type='current'>
<language version='1.6' flavor='static'>java</language>
<language version='1.7'>groovy</language>
<language version='4'>javascript</language>
</langs>
1. MarkupBuilder 的默认构造是输出到控制台,还可以接受其他的参数 IndentPrinter、PrintWriter、Writer,分别指明了不同的输出目的地。所以你可以此控制输出到 Socket 上,或是 Groovlet 的网页上等。
2. MarkupBuilder 的方法名是想当然的,如这里的 langs()、language() 方法,它们会生成同名的标签。
3. 闭包中的方法生成为外层方法(标签) 的子标签,例如,上面的 language() 生成了 langs() 对应标签 <langs> 的子标签 <language>
通过 MarkupBuilder 构建 HTML
import groovy.xml.MarkupBuilder
def html = new MarkupBuilder()
html.html{
head{
title("Links")
}
body{
h1("Here are my html bookmarks")
table(border:"1"){
tr{
th("what")
th("where")
}
tr{
td("groovy articles")
td{
a(href:"http://ibm.com/developerworks", "DeveloperWorks")
}
}
}
}
}
MarkupBuilder 非常适合用于同步构建简单的 XML 文档。对于更加高级的 XML 创建,Groovy 提供了一个
StreamingMarkupBuilder。通过它,您可以添加各种各样的 XML 内容,比如说处理指令、名称空间和使用 mkp 帮助对象的未转义文本(非常适合 CDATA 块)
def comment = "<![CDATA[<!-- address is new to this release -->]]>"
def builder = new groovy.xml.StreamingMarkupBuilder()
builder.encoding = "UTF-8"
def person = {
mkp.xmlDeclaration()
mkp.pi("xml-stylesheet": "type='text/xsl' href='myfile.xslt'" )
mkp.declareNamespace('':'http://myDefaultNamespace')
mkp.declareNamespace('location':'http://someOtherNamespace')
person(id:100){
firstname("Jane")
lastname("Doe")
mkp.yieldUnescaped(comment)
location.address("123 Main")
}
}
def writer = new FileWriter("person.xml")
writer << builder.bind(person)
解析XML文件
<lang type="current">
<language>java</language>
<language>groovy</language>
<language>javascript</language>
</lang>
def langs = new XmlParser().parse("language.xml")
println "type = ${langs.attribute("type")}"
langs.language.each{
println it.text()
}
解析字符串变量XML
def xml = """
<langs type='current' count='3' mainstream='true'>
<language flavor='static' version='1.5'>Java</language>
<language flavor='dynamic' version='1.6.0'>Groovy</language>
<language flavor='dynamic' version='1.9'>JavaScript</language>
</langs>
"""
def langs = new XmlParser().parseText(xml)
println "type = ${langs.attribute("type")}"
langs.language.each{
println it.text()
}
println langs.getClass() // class groovy.util.Node 继承自ArrayList
println langs
println langs.attributes().each{
println "-" * 15
println it.key
println it.value
}
def results = []
langs.language.each{
results << it.text()
}
println results
def version = langs.language*.attribute("version")
println version
XmlParser 返回 Node 和 NodeList,
XmlSlurper 返回一个 groovy.util.slurpersupport.GPathResult,不用调用attribute() text(),直接操作元素
def langs = new XmlSlurper().parseText(xml)
println langs.@count
langs.language.each{
println it
}
groovy.util.
NodeBuilder,用来创建一般任意对象的树状结构。看到了,它不在 groovy.xml 包之下,但它是一个 Builder,所以秉承了 Builder 的语法规则,而且还可用路径(对象导航)的方式来访问这个 Builder 实例中的节点或属性值。
import groovy.util.NodeBuilder;
someBuilder = new NodeBuilder(); //只有这么一个构建方法
root = someBuilder.users([balance:100]){ //这一块的语法完全同 MarkupBuilder
user([gender:"male"],"xace");
user("Joe"){
order(item:"Book");
}
}
// 因为 NodeBuilder 不预示着输出,所以需要显示的 print
println root;
println("-----访问节点-----");
// get() 方法返回包含指定名称的所有子节点
// 就像 DOM 的 getElementsByTagName("user")
users = root.get("user");
// 用路径(导航)的方式访问节点 同users = root.user
users.each(){
//用 name() 和 value() 分别访问节点的名称和值
println "${it.name()}:${it.value()}";
}
println("-----访问属性-----");
// attributes() 方法返回节点属性的一个 Map
println root.attribute("balance");
println root.@balance;
println("-----深度优先遍历节点-----");
root.depthFirst().each(){
println "${it.name()}:${it.attributes()}";
}
println("-----广度优先遍历节点-----");
root.breadthFirst().each(){
println "${it.name()}:${it.value()}";
}
println("用 Java 迭代器来遍历一个节点的子节点");
it = root.iterator();
while(it.hasNext()){
println it.next();
}