美文网首页
Groovy Xml 操作

Groovy Xml 操作

作者: zhaoyubetter | 来源:发表于2017-10-22 12:50 被阅读541次

    MarkupBuilder 创建xml文档

    参考:https://www.ibm.com/developerworks/cn/java/j-pg05199/index.html

    简单例子

    def mb = new MarkupBuilder()
    mb.book() {
           author('Lao Zhang')
           title('Groovy')
           publisher('中国邮电出版社')
           isbn("123456")
    }
    

    输出为:

    <book>
      <author>Lao Zhang</author>
      <title>Groovy</title>
      <publisher>中国邮电出版社</publisher>
      <isbn>123456</isbn>
    </book>
    

    输出到文件到book.xml文件

    def mb = new MarkupBuilder(new File('book.xml').newPrintWriter())
    mb.book() {     // 伪方法 book() 创建book元素
      ...
    

    简单例子2

    获取数据,生成 xml

    @Test
    void test2() {
        def data = ['11111111': ['Groovy', 'Lao Zhang', '人民邮电出版社'],
                    '22222222': ['Java In Mode', 'Zhang', '日报出版社'],
                    '33333333': ['Kotlin in Action', 'Jim', '对外出版社']]
    
        def mb = new MarkupBuilder(new File("book.xml").newPrintWriter())
        mb.library() {  // 伪方法创建library元素
            data.each { bk ->
                mb.book() {  // 创建book元素
                    title(bk.value[0])
                    author(bk.value[1])
                    publisher(bk.value[2])
                    isbn(number: bk.key)    // 新增number属性
                }
            }
        }
    }
    

    文件内容如下:

    <library>
      <book>
        <title>Groovy</title>
        <author>Lao Zhang</author>
        <publisher>人民邮电出版社</publisher>
        <isbn number='11111111' />
      </book>
      <book>
    ...
    

    XmlParser解析Xml

    将xml文档解析成树的节点,每个节点都有其名称,value,属性内容与子节点信息;

    @Test
    void test3() {
        def parser = new XmlParser()
        def doc = parser.parse("book.xml")
        println("${doc.book[0].title[0].text()}")
    
        // doc.book 传递了一个节点列表,可使用each方法了
        // 迭代xml内容
        doc.book.each() { bk ->
            println("${bk.title[0].text()}")
        }
    
        // 简化,输出所有title
        doc.book.title.each() { title ->
             println(title.text())
        }
    }
    

    获取节点属性值 ['@number']

    或者使用 Node.attribute("") 获取单个属性值,Node.attributes() 返回所有属性值映射

    @Testattriu
    void test4() {
        // 通过['@number'] 获取属性 isbn值
        def parser = new XmlParser()
        def doc = parser.parse("book.xml")
        doc.book.isbn.each() { it ->
            println(it['@number'])
        }
    }
    

    解析xml,并分组示例

    原xml如下,需要做成按 国籍 分组进行输出的 xml:

    <catalog>
        <cd>
            <title>Empire Burlesque</title>
            <artist>Bob</artist>
            <country>USA</country>
            <company>Columbia</company>
            <price>10.9</price>
            <year>1985</year>
        </cd>
        <cd>
            <title>Hide your heart</title>
            <artist>Jim</artist>
            <country>UK</country>
            <company>CBS Records</company>
            <price>8.9</price>
            <year>1988</year>
        </cd>
        <cd>
            <title>Still got the blues</title>
            <artist>Tom</artist>
            <country>UK</country>
            <company>Virgin Records</company>
            <price>10.2</price>
            <year>1990</year>
        </cd>
        <cd>
            <title>This is UK</title>
            <artist>Lee</artist>
            <country>UK</country>
            <company>Virgin Records</company>
            <price>12.20</price>
            <year>1990</year>
        </cd>
    </catalog>
    

    实现步骤:

    1. 解析原有xml,用map来存储xml结构;
    2. 将map中的xml结构,采用 markupbuilder 重新生成xml文件;
      代码如下:
    doc.cd.each() { cd ->
            if (countryMap.containsKey(cd.country[0].text())) {
                def yearMap = countryMap.get(cd.country[0].text())
                def year = cd.year[0].text()
                if (yearMap.containsKey(year)) {
                    yearMap[year] << cd.title[0].text()
                } else {
                    yearMap[year] = [cd.title[0].text()]  // 此为list
                }
                countryMap[cd.country[0].text()] << yearMap
            } else {
                // 因为是 map
                countryMap[cd.country[0].text()] = [(cd.year[0].text()): [cd.title[0].text()]]
            }
        }
        println(countryMap)
    }
    

    输出如下:

    [USA:[1985:[Empire Burlesque]], UK:[1988:[Hide your heart], 1990:[Still got the blues, This is UK]]]

    1. 生成分组的xml,代码如下:
    // 创建的新的xml
    def mb = new MarkupBuilder(new File('group.xml').newPrintWriter())
    mb.grouping() {     // 节点 grouping
        countryMap.each { country, yearMap ->
            mb.country(name: country) { // 节点 country
                yearMap.each { year, titleList ->
                    mb.year(year: year) {  // year节点
                        titleList.each {
                            title(it)  // <title>xxx</title>
                        }
                    }
                }
            }
        }
    }
    

    xml如下:

    <grouping>
      <country name='USA'>
        <year year='1985'>
          <title>Empire Burlesque</title>
        </year>
      </country>
      <country name='UK'>
        <year year='1988'>
          <title>Hide your heart</title>
        </year>
        <year year='1990'>
          <title>Still got the blues</title>
          <title>This is UK</title>
        </year>
      </country>
    </grouping>
    

    使用XmlSlurper解析xml

    使用 . 访问来操作xml节点,如需要访问属性 加 @
    参考:
    http://www.jianshu.com/p/6e95030fa55d

    xml 如下:

    <book>
      <author>Lao Zhang</author>
      <title>Groovy</title>
      <publisher>中国邮电出版社</publisher>
      <isbn parent="parment">123456</isbn>
    </book>
    
    def root = new XmlSlurper()
          .parse(this.getClass().getClassLoader().getResource("files/book.xml").getPath())
    println(root.isbn.@parent)      // 直接获取属性值,输出:parment
    

    忽略xml namespace的处理

    在Android的layout xml中,默认是有namespace的,比如我们解析一个布局文件获取其 attribute,如下代码:

    xml 文件如下

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:id="@+id/id_edittext_container"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:background="@color/didi_page_bg"
            android:orientation="horizontal">
    ...
    
    1. 通过 namespace的处理
    // 使用Groovy xml 来解析
    def root = new XmlParser().parse(this.getClass().getClassLoader()
              .getResource("files/address_search.xml").getPath())
    // 指定namespace
    def android = new Namespace("http://schemas.android.com/apk/res/android", "android")  
     root.each {
           println(it.attributes().get("android:layout_width"))  // 这里返回的是 null,获取不到
           // 通过namespace对象,结合[] 来访问属性值
           println(it.attributes()[android.layout_height])  // use namespace :android get layout_height
    }
    
    1. 忽略namesapce
    // 传入2个false
    def root = new XmlParser(false, false).parse(this.getClass().getClassLoader()
          .getResource("files/activity_address_search.xml").getPath())
    root.each {
          println(it.attributes().get("android:layout_width"))  // no problem
    }
    
    1. 例子:获取xml中的ID的2种方式
    def eachTxtFile(File file, closure) {
            if (file != null && file.exists()) {
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))
                try {
                    def line = null
                    while ((line = br.readLine()) != null) {
                        closure.call(line)
                    }
                } finally {
                    br?.close()
                }
            }
        }
    
    //////////////////////// 一行一行读,并使用正则 ===== 
        /**
         * // android 中 为 xml 指定id的方式如下:
         def str1 = "@+id/button1"
         def str3 = "@id/button3"
         def str2 = "@android:id/button2"
         */
        @Test
        void test2() {
            // 获取xml文件中的id value
            def file = new File(this.getClass().getClassLoader().getResource("files/activity_address_search.xml").getPath())
            def ids = []
            def pattern = ~/@((\+id)|(id)|(android:id))\/(.*)\"/
            eachTxtFile(file) { it ->
                def matcher = it =~ pattern
                if (matcher.find()) {
                    println("${matcher[0][5]}")     // 获取ID值
                }
            }
        }
    
    //////////////////////// 使用xmlParser ===== 
      @Test
        void test4() {
    // 使用Groovy xml 来解析
    def root = new XmlParser(false, false).parse(this.getClass().getClassLoader()
            .getResource("files/activity_address_search.xml").getPath())
      // 闭包的递归, 先定义,再赋值
            def eachNode 
            eachNode = { node ->
                if (node.attributes().containsKey("android:id")) {
                    println(node.attributes()["android:id"])  // no problem
                }
                node.value()?.each {
                    eachNode.call(it)
                }
            }
            eachNode.call(root)
        }
    

    相关文章

      网友评论

          本文标题:Groovy Xml 操作

          本文链接:https://www.haomeiwen.com/subject/dsleuxtx.html