1. Json 生成器 : JsonBuilder
import groovy.json.JsonBuilder
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
""""""
// json 生成器
def builder = new JsonBuilder()
builder.json{
first 'zeking'
last 'haha'
}
println builder // {"json":{"first":"zeking","last":"haha"}}
builder{
first 'zeking'
last 'haha'
}
println builder // {"first":"zeking","last":"haha"}
class Person{
def first
def last
}
def p = new Person(first: 'zekign',last:'haha')
// 转换对象为json数据
def b = new JsonBuilder(p)
println b.toString() // {"first":"zekign","last":"haha"}
println JsonOutput.toJson(p) // {"first":"zekign","last":"haha"}
// 格式化json数据
println JsonOutput.prettyPrint(JsonOutput.toJson(p))
//{
// "first": "zekign",
// "last": "haha"
//}
// 反序列化
def slurper = new JsonSlurper()
Person person = slurper.parseText(JsonOutput.toJson(p))
println person.first // zekign
println person.last // haha
2.xml 生成器 : MarkupBuilder
2.1 创建xml
xml_create.groovy
import groovy.xml.MarkupBuilder
import groovy.xml.StreamingMarkupBuilder
// xml 生成
"""<html><head m="a">hello</head></html>"""
//new File("baidu.html").write("https://www.baidu.com/".toURL().text)
def sw = new FileWriter(new File("normal.xml"))
def builder = new MarkupBuilder(sw)
builder.html{
mkp.comment("测试") // 注释
head("hello",m:"a"){
title("ZekingLee")
}
body{
}
}
//<html><!-- 测试 -->
// <head m='a'>hello
// <title>ZekingLee</title>
// </head>
// <body />
//</html>
def sb = new StreamingMarkupBuilder()
sb.encoding = 'UTF-8'
def closure = {
// 生成xml文件的版本和标识的方法
mkp.xmlDeclaration()
html{
head(id:1){
}
}
}
def sw2 = sb.bind(closure)
println sw2.toString()
// <?xml version='1.0' encoding='UTF-8'?>
// <html><head id='1'></head></html>
2.2 解析xml
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.androidprotobuf">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data android:name="hello" android:value="1"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
xml_parse.groovy
import groovy.xml.Namespace
// parser 是个Node 就是 manifest节点
def parser = new XmlParser().parse(new File("AndroidManifest.xml"))
// 1.需求:拿到activity节点的name属性
// name属性有一个 android: 的命名空间
//命名空间
def ns = new Namespace('http://schemas.android.com/apk/res/android','android')
Node node = parser.application[0].activity[0]
println node.attributes()[ns.name] // .MainActivity
// 2.移除meta-data节点,添加节点
// 获得application节点
Node node2 = parser.application[0]
//NodeList
Node meta = node2.'meta-data'[0]
node2.remove(meta)
node2.appendNode('meta-data',[(ns.name):'a',(ns.value):'b',(ns.hh):'hh'])
new XmlNodePrinter(new PrintWriter(new File("replace.xml"))).print(parser)
//<manifest package="com.example.administrator.androidprotobuf">
// <application android:allowBackup="true" xmlns:android="http://schemas.android.com/apk/res/android" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
// <activity android:name=".MainActivity">
// <intent-filter>
// <action android:name="android.intent.action.MAIN"/>
// <category android:name="android.intent.category.LAUNCHER"/>
// </intent-filter>
// </activity>
// <meta-data android:name="a" android:value="b" android:hh="hh"/>
// </application>
//</manifest>
//</manifest>
3. swing生成器 :SwingBuilder
import groovy.swing.SwingBuilder
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.WindowConstants
import java.awt.FlowLayout
// 使用groovy 写
def builder = new SwingBuilder()
def swing = builder.frame(title: '测试',size: [100,100],
layout: new FlowLayout(),defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE){
label(text:'文本')
button(text:'按钮',actionPerformed:{
})
}
swing.setVisible(true)
// 使用java代码写 ,对比一下,groovy简单很多
//def frame = new JFrame()
//frame.setTitle('测试')
//frame.setSize(100,100)
//frame.setLayout(new FlowLayout())
//frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
//new JLabel()
//new JButton().addActionListener {
//
//}
4. 模仿xm生成器 的 BuilderSupport自定义html生成器
MyBuildSupport.groovy
package builder
// 模仿xm生成器 的 MarkupBuilder 自定义生成器
class MyBuildSupport extends BuilderSupport{
class Node{
String name
String value
Map attr
def children // 将Node这个节点的所有子节点都保存到这个集合里面
Node(String name, String value, Map attr) {
this.name = name
this.value = value
this.attr = attr
children = []
}
//<xml key='value'/>
//<xml>xxx</xml>
def build(Writer writer){
// 生成xml
writer.write("<$name")
if (attr){
attr.each {
key,value->
writer.write(" $key='$value")
}
}
if (value || children){
writer.write(">")
if (value){
writer.write(value)
}
children.each{
it.build(writer)
}
writer.write("</$name>")
}else {
writer.write("/>")
}
}
}
def nodes
Writer writer
MyBuildSupport(Writer writer){
nodes = [:]
this.writer = writer
}
/**
* 节点与节点的关系
* @param parent 父节点
* @param child 子节点
*/
@Override
protected void setParent(Object parent, Object child) {
println "seParent $parent $child" // 这样是没有任何回调的
// 如何有回调,createNode 的 返回值会作为seParent的 参数 传递过来
}
/**
* 完成节点调用
* 通过这个方法可以知道
* 节点之间的关系 也可以知道 节点的完成情况
* @param parent
* @param node
*/
@Override
protected void nodeCompleted(Object parent, Object node) {
super.nodeCompleted(parent, node)
println "nodeCompleted $parent $node"
def currentNode = nodes[node]
if (parent){
nodes[parent].children << currentNode
}else{
// 构建需要的格式
currentNode.build(writer)
}
}
@Override
protected Object createNode(Object name) {
return createNode(name,null,null)
}
@Override
protected Object createNode(Object name, Object value) {
return createNode(name,null,value)
}
@Override
protected Object createNode(Object name, Map attributes) {
return createNode(name,attributes,null)
}
@Override
protected Object createNode(Object name, Map attributes, Object value) {
println("create Node:$name $value $attributes")
nodes.put(name,new Node(name,value,attributes))
return name
}
}
MyBuilderTest.groovy
package builder
StringWriter sw = new StringWriter()
def builder = new MyBuildSupport(sw)
builder.html{
head("zeking",key:'value'){
title("Test")
}
body{
}
x{
y{
z{
}
}
}
}
println(sw)
//create Node:html null null
//create Node:head zeking [key:value]
//seParent html head
//create Node:title Test null
//seParent head title
//nodeCompleted head title
//nodeCompleted html head
//create Node:body null null
//seParent html body
//nodeCompleted html body
//create Node:x null null
//seParent html x
//create Node:y null null
//seParent x y
//create Node:z null null
//seParent y z
//nodeCompleted y z
//nodeCompleted x y
//nodeCompleted html x
//nodeCompleted null html
//<html><head key='value>zeking<title>Test</title></head><body/><x><y><z/></y></x></html>
5. 模仿swing生成器 的 FactoryBuilderSupport自定义html生成器
MyFactoryBuilderSupport.groovy
package builder
// 模仿swing生成器
// 工厂 buildsupport工厂
class Node{
String name
String value
Map attr
def children // 将Node这个节点的所有子节点都保存到这个集合里面
Node(String name, String value, Map attr) {
this.name = name
this.value = value
this.attr = attr
children = []
}
//<xml key='value'/>
//<xml>xxx</xml>
def build(Writer writer){
// 生成xml
writer.write("<$name")
if (attr){
attr.each {
key,value->
writer.write(" $key='$value")
}
}
if (value || children){
writer.write(">")
if (value){
writer.write(value)
}
children.each{
it.build(writer)
}
writer.write("</$name>")
}else {
writer.write("/>")
}
}
}
class MyFactoryBuilderSupport extends FactoryBuilderSupport{
{
def nodeFactory = new NodeFactory()
// 注册html的工厂
registerFactory('html',new NodeFactory())
registerFactory('head',new NodeFactory())
}
}
class NodeFactory extends AbstractFactory{
def name
/**
* 返回的参数就是我们调用html方法的结果
* @param builder
* @param name
* @param value
* @param attributes
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
@Override
Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) throws InstantiationException, IllegalAccessException {
println "newInstance $name $value $attributes"
this.name = name
return new Node(name,value,attributes)
}
// 在newInstance 之后调用
// 处理属性的方法
@Override
boolean onHandleNodeAttributes(FactoryBuilderSupport builder, Object node, Map attributes) {
//如果返回true会从newInstance返回中寻找attributes对应key的属性
return false
}
// false 表示可以接收闭包
// true 表示不能接收
@Override
boolean isLeaf() {
return super.isLeaf()
}
// 设置当前节点的父节点
@Override
void setParent(FactoryBuilderSupport builder, Object parent, Object child) {
super.setParent(builder, parent, child)
println "$name setParent ${parent.name} ${child.name}"
}
// 设置当前节点的子节点
@Override
void setChild(FactoryBuilderSupport builder, Object parent, Object child) {
super.setChild(builder, parent, child)
println "$name setChild ${parent.name} ${child.name}"
parent.children << child
}
}
MyFactoryBuilderSupportTest.groovy
package builder
//new MyFactoryBuilderSupport().xml{
//
//}
// 会报错,因为我没有注册xml工厂
//五月 16, 2018 10:11:22 下午 groovy.util.FactoryBuilderSupport createNode
//警告: Could not find match for name 'xml'
//Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.Object.xml() is applicable for argument types: (java.util.Collections$EmptyMap, null) values: [[:], null]
//Possible solutions: dump(), any(), wait(), find(), grep(), is(java.lang.Object)
//groovy.lang.MissingMethodException: No signature of method: java.lang.Object.xml() is applicable for argument types: (java.util.Collections$EmptyMap, null) values: [[:], null]
//Possible solutions: dump(), any(), wait(), find(), grep(), is(java.lang.Object)
// at builder.MyFactoryBuilderSupportTest.run(MyFactoryBuilderSupportTest.groovy:5)
//new MyFactoryBuilderSupport().html{
//
//}
// 不会报错,只是警告 这就是registerFactory 的作用
//五月 16, 2018 10:11:01 下午 groovy.util.FactoryBuilderSupport createNode
//警告: Factory for name 'html' returned null
StringWriter sw = new StringWriter()
new MyFactoryBuilderSupport().html{
head('Zeking',key:'value'){
}
}.build(sw)
println sw
//newInstance html null [:]
//newInstance head Zeking [key:value]
//head setParent html head
//html setChild html head
//<html><head key='value>Zeking</head></html>
6. FactoryBuilderSupport 和 BuilderSupport 的区别
FactoryBuilderSupport 适用于 固定的方法,必须注册工厂
而BuilderSupport 可以用户高度自定义
FactoryBuilderSupport不适合创建html 但是会非常适合创建swing