GroovyでXPath
Groovyはあまり関係ないかもしれない。
読み込みたいデータ。
String books = ''' <books> <book> <id>01</id> <name>book1</name> </book> <book> <id>02</id> <name>book2</name> </book> <book> <id>03</id> <name>book3</name> </book> <book> <id>04</id> <name>book4</name> </book> </books> '''
// この辺のやり方はGroovyのドキュメントから def builder = DocumentBuilderFactory.newInstance().newDocumentBuilder() def inputStream = new ByteArrayInputStream(books.bytes) def bookData = builder.parse(inputStream).documentElement def factory = XPathFactory.newInstance() def xpath = factory.newXPath() // 「//」は全要素に対して // NODESET指定すると、text()の取得でも#textノードの取得になったので、ループ内でtextを再取得。NODESET指定の時は普通はtext()はつけなくて良い // 第三引数のNODESETがないと最初のnodeだけ取得される。(book1のnode) def nameStrs = xpath.evaluate("//name/text()",bookData,XPathConstants.NODESET) nameStrs.each{ Node n = it println "name:" + n.getTextContent() } // 「/」は絶対パス def bookNames = xpath.evaluate("/books/book/name",bookData,XPathConstants.NODESET) bookNames.each{ // 先頭のスラッシュなしは相対パス println "bookName:" + xpath.evaluate("text()",it) }
XMLのノードがbooks配下にbookの繰り返しようにきれいに並んでいない場合。
String settingXml = ''' <settings> <id>id01</id> <name>name01</name> <category>cat01</category> </settings> '''
settingsが親という共通の条件を指定することでループ
def inputStream = new ByteArrayInputStream(settingXml.bytes) def settings = builder.parse(inputStream).documentElement def elems = xpath.evaluate("//*[parent::settings]",settings,XPathConstants.NODESET) elems.each{ println it.getNodeName() + ":" + xpath.evaluate("text()",it) // 上と同じ // println it.getNodeName() + ":" + it.getTextContent() }
参考:
XPathについて
http://pearl-white.hp.infoseek.co.jp/xpath/
https://developer.mozilla.org/ja/DOM/element