Groovy12_Jsonxmlswing与生成器

Posted 李樟清

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Groovy12_Jsonxmlswing与生成器相关的知识,希望对你有一定的参考价值。

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

以上是关于Groovy12_Jsonxmlswing与生成器的主要内容,如果未能解决你的问题,请参考以下文章

Groovy05_Groovy方法调用与运算符重载

Groovy06_Groovy方法扩展与脚本调用

Groovy06_Groovy方法扩展与脚本调用

IDEA连接数据库生成实体类方法与定制Groovy生成脚本

Groovy02_字符串与循环

Groovy10_元编程(方法合成与委托)