2010年3月25日木曜日

[Scala] Elemのlabel(要素名)を書き換える

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
こんな感じか?
def changeTagName[T >: Node](from: String, to: String)(in: T): T = in match {
  case Elem(p, l, a, ns, child @ _*) => 
    val label = if (l == from) to else l
    Elem(p, label, a, ns, child.map(changeTagName(from, to)(_)): _*)
  case x => x
}

使用例

scala> val hoge2moge = changeTagName("hoge", "moge") _
scala> hoge2moge: (scala.xml.Node) => scala.xml.Node = <function>

scala> hoge2moge(<pre:hoge attr="value">parentText<child:hoge>childtext</child:hoge></pre:hoge>)
scala> res17: scala.xml.Node = <pre:moge attr="value">parentText<child:moge>childtext</child:moge></pre:moge>

追記:さらに汎用化してみた

高階関数化して、引数に名前を変更するための関数を渡せるようにした。
def changeTagName[T >: Node](changeFunc: (String) => String)(in: T): T = in match {  
  case Elem(p, l, a, ns, child @ _*) =>   
    Elem(p, changeFunc(l), a, ns, child.map(changeTagName(changeFunc)(_)): _*)  
  case x => x  
}

使用例

お題はこちら
scala> val c = changeTagName(s => if (List("moge", "koge").contains(s)) "bege" else s) _
c: (scala.xml.Node) => scala.xml.Node = <function>

scala> c(x)
res6: scala.xml.Node =
<lage>
         <hoge>
           <bege></bege>
           <bege></bege>
         </hoge>
         <hoge>
           <bege></bege>
           <bege></bege>
         </hoge>
       </lage>

23:52 さらにちょっと修正

flatMap使えば別にNodeSeq渡せることに気がついた。
def changeTagName(changeFunc: (String) => String)(in: NodeSeq): NodeSeq = in match {  
  case Elem(p, l, a, ns, child @ _*) =>   
    Elem(p, changeFunc(l), a, ns, child.flatMap(changeTagName(changeFunc)(_)): _*)  
  case x => x  
}

0 件のコメント:

コメントを投稿