2009年12月21日月曜日

XmlSlurperで属性をそのままテキストだけを入れ替える。

GroovyではXML処理に、XmlPerserとXmlSlurper(他いろいろ……)が用意されてあって、ただ読み込む場合はXmlSlurper、編集するなり書き換える場合はXmlPerserを使うように、って棲み分けがされている。
だけどSlurperでもいちおう簡単な編集機能は用意されてるみたいで、
XmlSlurper を使った XML の加工 - なんとなくな Developer のメモ
  • 要素の追加: appendNode メソッドを使用
  • 属性の追加: @属性名 に値を設定
  • 要素の置換: replaceNode メソッドを使用
  • 要素の削除: replaceNode メソッドを使用(実装を空にする)

となるらしい。なのでこれを使ってXMLのテキストを入れ替えようと思った。
import groovy.xml.StreamingMarkupBuilder

String myXml='''<root>
<species order="甲虫目" family="コガネムシ科">カブトムシ</species>
<species order="甲虫目" family="カミキリムシ科">シロスジカミキリ</species>
<species order="チョウ目" family="アゲハチョウ科">アゲハチョウ</species>
</root>'''

def doc = new XmlSlurper().parseText(myXml)

doc.species[0].replaceNode{species('クロカナブン')}

//テキストに戻す
StreamingMarkupBuilder builder = new StreamingMarkupBuilder()
builder.encoding = "UTF8"
def newXml = builder.bind{mkp.yield doc};

println(newXml)
こうすると、当然「カブトムシ」の要素ごと書き変わってしまうので、クロカナブンの目と科がわからなくなってしまう。少し(かなり)考えて、属性を保存して、新しく入れ替える要素にコピーできるんじゃないかな?
import groovy.xml.StreamingMarkupBuilder

String myXml='''<root>
<species order="甲虫目" family="コガネムシ科">カブトムシ</species>
<species order="甲虫目" family="カミキリムシ科">シロスジカミキリ</species>
<species order="チョウ目" family="アゲハチョウ科">アゲハチョウ</species>
</root>'''

def doc = new XmlSlurper().parseText(myXml)
//assert doc.species[0] == 'カブトムシ'

Map attr = doc.species[0].attributes();
//assert attr == [family:'コガネムシ科', order:'甲虫目']

//ノードを置き換える時に属性をそのままコピー
doc.species[0].replaceNode{species('クロカナブン',attr)}

//テキストに戻す
StreamingMarkupBuilder builder = new StreamingMarkupBuilder()
builder.encoding = "UTF8"
def newXml = builder.bind{mkp.yield doc};

println(newXml)
これでOK。属性のマップをそのまま後ろに入れるだけで属性になる。へー。
結果はこう。
<root><species family='コガネムシ科' order='甲虫目'>クロカナブン</species><species family='カミキリムシ科' order='甲虫目'>シロスジカミキリ</species><species family='アゲハチョウ科' order='チョウ目'>アゲハチョウ</species></root>

0 件のコメント: