今天先跟大家分享Groovy如何處理DOM結構的文件,有兩條路,一條是引用原有的java API(javax.xml.parsers.DocumentBuilderFactory),當作對照組,另外一條路Groovy自行改寫過的groovy.xml.dom.DOMCategory,可以很直觀的處理DOM架構文件
首先,先把今天的XML po上來,這是我在寫Java FX2應用程式中其中一個FXML,存成XML作為今日範例:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="387.0" prefWidth="451.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="controller.RoutineCopyController">
<!-- TODO Add Nodes -->
<bottom>
<Label alignment="CENTER" contentDisplay="CENTER" text="Copy Right By DNE I&C" BorderPane.alignment="CENTER" />
</bottom>
<center>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="20.0">
<children>
<ProgressIndicator fx:id="progressIndicator" focusTraversable="false" prefHeight="132.0" prefWidth="475.0" progress="0.0" />
<Label fx:id="copyMessage" prefHeight="34.0" prefWidth="4750" text="" />
<Button fx:id="copyButton" mnemonicParsing="false" onAction="#beginCopy" text="Copy" />
</children>
</VBox>
</center>
<top>
<Label alignment="CENTER" contentDisplay="CENTER" text="Daily Copy Program" textAlignment="CENTER" BorderPane.alignment="CENTER" />
</top>
</BorderPane>
再來是沿用java API來讀出不同層的tag,範例如下:
import javax.xml.parsers.DocumentBuilderFactory
import static org.w3c.dom.Node.*
def factory=DocumentBuilderFactory.newInstance()
def builder=factory.newDocumentBuilder()
//建立Factory&Builder
def doc=builder.parse(new FileInputStream('D:\\groovy\\mygroovy\\src\\layout.xml'))
//讀入XML
def root=doc.documentElement //建立DOM Tree
String tagInfo(node){//定義一方法判斷及return對應的node文字
switch(node.nodeType){//org.w3c.dom.node定義三種node
case ELEMENT_NODE: //node名稱
return "${node.nodeName}"
case ATTRIBUTE_NODE://讀出屬性以及值
return "Tag Attribute:${node.nodeName}=${node.nodeValue}"
case TEXT_NODE://這個沒看過,我只知道value,要再研究一下
return "Tag Value: ${node.nodeValue}"
}
return "Some other type: ${node.nodeType}"
}
println "Root Tag ${tagInfo(root)}" //最上層
def subroot=root.childNodes.find{it.nodeName =='center'}
//第二層,可用closure找到指定的tag
println "Tag:${tagInfo(root)}'s child is ${tagInfo(subroot)}"
def vBox=subroot.childNodes.item(1)
//第三層,除了用字串指定,也可以用index
println "Tag:${tagInfo(subroot)}'s child is ${tagInfo(vBox)}"
def vBoxAtt=vBox.attributes.getNamedItem('alignment') //讀出屬性以及值
println tagInfo(vBoxAtt)
執行結果:
Root Tag BorderPane
Tag:BorderPane's child is center
Tag:center's child is VBox
Tag Attribute:alignment=CENTER
第二種用Groovy把org.w3c.dom.Node相關處理寫成更直覺的DOMCategory class讓我們在處理DOM文件時可以直接用文件中的tag名稱存取資訊,範例如下
import groovy.xml.DOMBuilder
import groovy.xml.dom.DOMCategory //配合DOMBuilder把org.w3c.dom.Node物件包裝更直觀
def doc=DOMBuilder.parse(new FileReader('D:\\groovy\\mygroovy\\src\\layout.xml'))
//DOMBuilder搭配的是FileReader,跟FileInputStream在這次的範例功能大同小異
def root=doc.documentElement
//建立DOM Tree
use(DOMCategory){ //使用DOMCategoy來處理{}內的statement
println "Root Tag is ${root.name()}"
println "Subroot Tag is ${root.center[0].name()}"
println "${root.center[0].name()}'s child is ${root.center.VBox[0].name()}"
println "${root.center.VBox[0].name()} has its child called "+
"${root.center.VBox.children[0].name()}, "+
"and its grandchild called ${root.center.VBox.children.ProgressIndicator[0].name()}"
}
執行結果:
Root Tag is BorderPane
Subroot Tag is center
center's child is VBox
VBox has its child called children, and its grandchild called ProgressIndicator
兩者相比,後者語法精簡很多,也更簡單的就可以存取到更深一層的tag