2012年12月26日

Grails / Groovy 使用 XmlParser 快速產生測試用的範例內容

在 Grails 的開發階段,我們習慣將 development 與 production 分別使用不同資料庫來源(DataSource)。在開發階段我喜歡保留預設的 H2 Database Engine,這是純 Java 開發的資料庫引擎,畢竟是 Grails 官方的選項,它與 Grails 的 GORM(底層是 Hibernate)一起運作不太會有問題。H2 相當輕量易用,可以只將開發階段測試用的資料放在記憶體,重新啟動測試伺服器後就會一切從頭開始。

這是預設的 H2 DataSource 設定(DataSource.groovy)。

    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }

但是在開發階段,我們仍希望有一些資料,這樣比較容易設計 Controller 及 Web UI 介面。假設有一個 Model (Grails 的 Domain Class)是 Post(Post.groovy):

    class Post {
        String title
        String content
    }

這個時候有幾種方式,可以在開發階段建立測試資料:
  1. 自己動手 KEY-IN...但是這太蠢了,萬一想要建一百筆,每次重新啟動 Server 都要打字打到手抽筋。
  2. 改用 MySQL 或其他資料可以永久保存的 DataSource,但這樣會讓開發環境的建立變得麻煩。
  3. 在 BootStrap.groovy 使用樣板或隨機產生的資料來灌水,這樣一切就變得更自動化。

當然,我們會使用第三種作法,這樣可以保持開發環境容易建立、使用與可攜性,但如果能再加入一點手腳,讓產生的資料看起來稍微有點意義,這樣一切就更美好了。

以 Post (發佈文章)的內容來說,我們可以直接找個 RSS/ATOM 來源撈資料,再把內容灌到資料庫,有了 Groovy 超簡單的 XmlParser 幫忙,這項需求的處理只要簡單的幾行 code 就搞定:

資料來源範例(Google 新聞):
https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss

先用 Groovy 寫一小片段 Scripting 測試程式:

```groovy
    def url = 'https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss'
 
    def xml = new XmlParser().parse(url)
 
    def items = [:]
 
    xml.channel[0].item.each {
        item->
     
        items << [
            title: item.title[0].value().first(),
            content: item.description[0].value().first().replaceAll("<(.|\n)*?>", '')
        ]
    }
```

接下來在 Grails 的 BootStrap.groovy 設定開發階段(development environment)專用的文章自動擷取,Groovy 的 XmlParser 搭配 Grails 的 GORM 非常簡單!這個範例順便將 HTML 原始碼的標籤,利用 Groovy 內建的字串 Regular Expression 清理乾淨。

```grails
    class BootStrap {
        def init = { servletContext ->
            environments {
                development {
                    //自動產生文章 RSS from Google News
                    def url = 'https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss'
                    def xml = new XmlParser().parse(url)
                    def i = 0
                    xml.channel[0].item.each {
                        item->
                     
                        new Post(
                            title: item.title[0].value().first(),
                            content: item.description[0].value().first().replaceAll("<(.|\n)*?>", ''),
                        ).save(flush: true)
                    }
                }
            }
        }
    }
```

沒有留言:

張貼留言

lyhcode by lyhcode
歡迎轉載,請務必註明出處!