2013-05-14 62 views
0

鑑於這種XML:轉化是根據它的兄弟的XML元素,使用scala.xml.transform.RuleTransformer

<root> 
<item> 
    <discriminator>d1</discriminator> 
    <target>t1</target> 
    <subitem> 
     <incomplete></incomplete> 
    </subitem> 
    <subitem> 
     <incomplete></incomplete> 
    </subitem> 
</item> 
<item> 
    <discriminator>d2</discriminator> 
    <target>t2</target> 
    <subitem> 
     <incomplete></incomplete> 
    </subitem> 
</item> 
</root> 

我需要改造它使得:
1)對於每個<item>,的<target>文本根據<discriminator>中的文字進行修改。
2)爲每個<incomplete>添加一些文字內容。

基於其他SO帖子,到目前爲止,我已經想出了2)的解決方案,使用RewriteRuleRuleTransformer。它是這樣的:

object completeIncomplete extends RewriteRule { 
     override def transform(n: Node): Seq[Node] = n match { 
     case Elem(_, "incomplete", _, _, _*) => 
      <incomplete>content</incomplete> 
     case other => other 
     } 
    } 
object transform extends RuleTransformer(completeIncomplete) 
transform(xml) 

這似乎很好地工作,但我不知道:

  • 如何實現1)(修改基於其兄弟姐妹)的元素
  • 如何結合兩個處理步驟。那就是:在這種情況下有兩個不同的RewriteRule-s是否有意義?這是浪費嗎?在單次迭代中是否可以/可行地實現兩種轉換?

爲1),我試圖模式匹配兒童的名單,像這樣:

case Elem("", "item", _, _, [email protected]("", "discriminator", _, _, _*)) 
    if discriminate(disc) => //...? 

或本:

case [email protected]("", "item", _, _, _*) 
    if discriminate(item \ "disc") => //..? 

但是,這沒有奏效所以好,因爲我不知道如何重新創建整個項目只有替換<target>

我不甚至知道在這種情況下是否需要匹配<item>。但如果是這樣,我能否以某種方式實現其<incomplete>兒童的轉變?

這裏的正確方法是什麼?

回答

1

看看這對你的作品:

override def transform(n: Node): Seq[Node] = n match { 

    case el @ Elem(_, "item", _, _, _*) => 
     val children = el.child 
     val disc = children.find(_.label == "discriminator") 
     val content = children.collect{ 
     case el @ Elem(_, "target", _, _, _*) => 
      <target>{el.text + disc.map(_.text).getOrElse("")}</target> 
     case e:Elem => e 
     } 
     <item>{content}</item> 

    case el @ Elem(_, "incomplete", _, _, _*) => 
     <incomplete>some content</incomplete> 
    case other => other 
    } 

的XML結構是不變的,所以當你是一個特別的元素,你不能訪問它的父。因此,我選擇通過停止item來代替您的問題#1並更換其子內容。我希望這是你正在尋找的。