Groovy JSON XML操作

JSON解析

JSON在互联网应用中越来越多的承担起客户端服务器之间的通信数据格式,相对XML等数据根式它的内容更加紧凑,占用的带宽更低,很受开发者的青睐。Groovy中生成Json和解析Json为对象都非常简单,生成Json只需要将对象传递给JsonOutput的toJson方法,解析Json语句的时候调用JsonSlurper.pareseXXX()方法。

class Person {
    String name
    int age

    String toString() {
        return "$name = $age"
    }
}

def list = [new Person(name: 'zhangsan', age: 20), new Person(name: "lisi", age: 30)]

def json = JsonOutput.toJson(list)
println json

def jsonSlurper = new JsonSlurper()
def jsonList = jsonSlurper.parseText(json)
println jsonList[0].age

除了上面的Groovy内置接口,Java针对Json的各种类库都可以在Groovy中调用,比如Gson、fast-json等类库,不过需要在gradle文件用引用它们。

XML解析

XML的生成和解析也分为Java版本和Groovy版本,Java版本的主要分成SAX和DOM两大类解析方式,使用Groovy的XMLSlurper对象的parseXXX方法,最终解析出来的对象支持GPath方式的访问,能够直接以”.”号引用子对象,“@”符号可以引用属性值。

<?xml version="1.0" encoding="UTF-8" ?>
<books>
    <book id="100" price="72" author="xys">Android Heros</book>
    <book id="200" price="50" author="ryg">Android Develop</book>
    <book id="300" price="69" author="lg">Crazy Android</book>
</books>

SAX解析

SAX解析是从头开始读取XML文件内容,当遇到文档开头调用startDocument回调,遇到文档结尾调用endDocument回调,节点开头结尾时会会调用startElement和endElement,节点的属性都被封装在Attributes对象里随着startElement传入,对于节点内部的文案则是回调character回调。SAX解析不需要一开始就把所有的数据读入到内存中去,可以解析较大的文件,适用于内存相对紧张的系统;缺点是无法随机访问数据,必须从头开始直到读取数据位置。

task saxXML {
    def saxFactory = SAXParserFactory.newInstance()
    def saxParser = saxFactory.newSAXParser()
    def list = []
    def book
    def handler = new DefaultHandler() {
        @Override
        void startDocument() throws SAXException {
            super.startDocument()
        }

        @Override
        void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes)
            if (qName.equals("book")) {
                book = new Book()
                book.id = Integer.parseInt(attributes.getValue("id"))
                book.author = attributes.getValue("author")
                book.price = Double.parseDouble(attributes.getValue("price"))
            }
        }

        @Override
        void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length)
            if (book != null) {
                book.name = new String(ch, start, length)
            }
        }

        @Override
        void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName)
            if ("book".equals(qName)) {
                list.add(book)
                book = null
            }
        }

        @Override
        void endDocument() throws SAXException {
            super.endDocument()
        }
    }

    saxParser.parse(new File("books.xml"), handler)
    list.forEach {
        println it
    }
}

// Book{id=100, price=72.0, author='xys', name='Android Heros'}
// Book{id=200, price=50.0, author='ryg', name='Android Develop'}
// Book{id=300, price=69.0, author='lg', name='Crazy Android'}

DOM解析

DOM解析会先将整个XML文档读入到内存中去,之后在根据文档结构构建Document Object Model文档对象模型,也就是多个标签的嵌套,最后通过文档操作随机访问DOM里的元素数据。

用途
Node Element和TextElement的基础类
Element 节点类型
Text 文本节点
Document 代表整个XML文档,代表DOM tree
task domXML {
    def domParser = DocumentBuilderFactory.newInstance().newDocumentBuilder()
    def xmlFile = new File("books.xml")
    def document = domParser.parse(xmlFile)
    document.getDocumentElement().normalize()
    def nodeList = document.getElementsByTagName("book")
    def list = []

    for (node in nodeList) {
        def element = (Element) node
        def book = new Book()
        book.id = Integer.parseInt(element.getAttribute("id"))
        book.author = element.getAttribute("author")
        book.price = Double.parseDouble(element.getAttribute("price"))
        book.name = element.firstChild.getTextContent()
        list.add(book)
    }

    list.forEach {
        println it
    }
}

// Book{id=100, price=72.0, author='xys', name='Android Heros'}
// Book{id=200, price=50.0, author='ryg', name='Android Develop'}
// Book{id=300, price=69.0, author='lg', name='Crazy Android'}

XMLSlurper解析

需要注意的是Slurper.parse返回的是XML的根节点,只有节点可以通过“.”操作符访问,如果在某个节点下有多个相同类型的节点,使用”.子节点名”得到的其实是所有子节点的数组,注意示例中的books.book就是根节点下的所有book节点。

task slurperXML {
    println "Slurper XML"
    def books = new XmlSlurper().parse(new File("books.xml"))

    for (book in books.book) {
        println "$book ,price is ${book.@price} yuan"
    }
}

// Slurper XML
// Android Heros ,price is 72 yuan
// Android Develop ,price is 50 yuan
// Crazy Android ,price is 69 yuan

XML文件写入

Groovy对Java的File对象做了扩展,能够很方便地读取文件内容,只要调用withXXXStream就会在后面的闭包里将封装了File的XXXStream传入,降低了用户使用File对象的复杂度。

task testFile {
    def file = file("proguard-rules.pro")
    // 直接读取整个文件
    println file.text

    // 一行一行读取文件
    file.eachLine {
        println it
    }

    // 只保留包含-keep的行输出到控制台
    file.filterLine {
        it.contains("-keep")
    }.writeTo(new PrintWriter(System.out))
}

上面的读取和过滤数据行相对比较简单,不再多做说明,接着来看groovy下如何生成XML数据并且保存到本地文件里。MarkupBuilder适合于构建中小型的XML文档,而StreamingMarkupBuilder适合构建超大型的XML文档,两者用法类似这里只演示使用MarkupBuilder来生成XML数据。

task makeUpXML {
    def writer = new FileWriter("users.xml")
    def makeup = new groovy.xml.MarkupBuilder(writer)
    makeup.users(id: "root") {
        user(name: "zhangsan", age: 16)
        user(name: "lisi", age: 30)
    }
}

<users id='root'>
  <user name='zhangsan' age='16' />
  <user name='lisi' age='30' />
</users>

猜你喜欢

转载自blog.csdn.net/xingzhong128/article/details/80272302