2012年9月30日 星期日

Groovy 與 XML 的相遇(一) : MarkupBuilder + XmlSlurper

用Groovy 來產生 xml 再簡單不過了。雖然以前的 dom4j也是用物件的方式操作,但你要做的功夫相當的多。 先貼Java要怎麼寫…大約51行

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

public class CreateXml {
  public static void main(String[] args) {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.newDocument();

      Element root = doc.createElement("root");      
      doc.appendChild(root);

      Element star1 = doc.createElement("star");
      Text text1 = doc.createTextNode("布萊德彼特");
      star1.appendChild(text1);
      root.appendChild(star1);

      Element star2 = doc.createElement("star");
      Text text2 = doc.createTextNode("小勞勃道尼");
      star2.appendChild(text2);
      langs.appendChild(star2);

      Element star3 = doc.createElement("star");
      Text text3 = doc.createTextNode("基努李維");
      star3.appendChild(text3);
      langs.appendChild(star3);

      // Output the XML
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer transformer = tf.newTransformer();
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
      StringWriter sw = new StringWriter();
      StreamResult sr = new StreamResult(sw);
      DOMSource source = new DOMSource(doc);
      transformer.transform(source, sr);
      String xmlString = sw.toString();
      System.out.println(xmlString);
    }catch(ParserConfigurationException pce) {
      pce.printStackTrace();
    } catch (TransformerConfigurationException e) {
      e.printStackTrace();
    } catch (TransformerException e) {
      e.printStackTrace();
    }
  }
}
雖然非常容易理解,一個一個物件生成,但這麼單純的事,要花51行來寫,覺得你快要死了嗎? (況且他們的屬性我還沒有加進去哩……) 來一點輕鬆的吧。先寫了一個第一版,15行,很棒了吧??

import groovy.xml.MarkupBuilder
import groovy.util.XmlSlurper
def file = new File("d:\\test.xml")
def objs = [
    [ age: 22, name: "布萊德彼特", blood: "A" ],
    [ age: 26, name: "小勞勃道尼", blood: "C" ],
    [ age: 24, name: "基努李維", blood: "B" ] ]
def b = new MarkupBuilder(new FileWriter(file))
b.root {
    objs.each { o ->
        star(age: o.age , blood:o.blood ,  o.name) {          
        }
    }
}
如果不要先把資料弄成集合 ( 雖然這樣比較容易看的懂 ),要寫的行數更少…

def xml = new groovy.xml.MarkupBuilder(new FileWriter("d:\\test.xml"))
xml.root(){
  star(age: 22, blood: "A" , "布萊德彼特")
  star(age: 26, blood: "C" , "小勞勃道尼")
  star(age: 24, blood: "B" , "基努李維")
}

對,你沒看錯,就是6行。 除了行數變少之外,易讀性完全破表。 root 並不是一個死的方法,你將它改成stars,那麼產出的xml的根節點就叫做stars了。裡面所有的東西都能改,只要你結構掌握住了,xml 某一個節點要加新的屬性,易如反掌! 維護程式的人,你覺得他看上面的51行容易理解,還是下面的6行呢?

我們都知道重構的重要。若只是為了把原來就繁複的語法歸類而重構,那為何不一開始就精簡語法? 

這樣精簡的xml 語法,很大的功勞一樣是用閉包做的。程式人員只要專心在資料面,如何產生xml 的部份並非你的價值所在。除非你是開發 xml parser 的人,否則不要沉醉在自己高深的50行程式中。這裡面並沒有價值。再一次強調,就像醫生的價值在於醫好別人的病,不在於你會用幾種手術刀。若你可以空手就取出腫瘤,30秒結束回家吃飯,沒有病人會想抱怨的。

沒有留言:

張貼留言