如何只转换scala中xml文件的顶级节点(而不是后代)

时间:2014-08-06 21:30:08

标签: xml scala transform

我有一些xml,其中顶层有一个<id/>节点,也有后代节点。有没有办法让我更改顶级而不是更低级别的值?

示例输入

val inputXml = 
  <top>
    <id>123</id>
    <a>
      <id>innerId</id>
    </a>
    <b>other info</b>
    <c>
      <id>444</id>
    </c>
  </top>

我想看到的输出是:

val expectedOutputXml =
  <top>
    <id>999</id>
    <a>
      <id>innerId</id>
    </a>
    <b>other info</b>
    <c>
      <id>444</id>
    </c>
  </top>

我尝试过像这样使用RewriteRule:

import scala.xml.transform.{RewriteRule, RuleTransformer}
import scala.xml.{Elem, Node, NodeSeq}

def changeTopId(root:Node, newId:String) = {

  val dontChg = root \ "_" filter {e => List("a", "b").contains(e.label)}

  object t1 extends RewriteRule{
    override def transform(n: Seq[Node]): Seq[Node] = n match {
      case e:Elem if dontChg.contains(e) => e
      case e:Elem if e.label == "id" => <id>{newId}</id>
      case other => other
    }
  }
  object changeTopOne extends RuleTransformer(t1)

  changeTopOne(root)
}

但它影响所有<id/>个节点,导致:

scala> changeTopId(inputXml, "999")
res1: scala.xml.Node =
<top>
    <id>999</id>
    <a>
      <id>999</id>
    </a>
    <b>other info</b>
    <c>
      <id>999</id>
    </c>
  </top>

由于

1 个答案:

答案 0 :(得分:1)

原来我不需要重写规则。 这是一个5行解决方案。

val xs = (inputXml \ "_") map {
  case e: Elem if e.label == "id" => <id>999</id>
  case other => other
}

inputXml.copy(child=xs)

结果值(手动格式化)

scala.xml.Elem =
<top>
    <id>999</id>
    <a>
        <id>innerId</id>
    </a>
    <b>other info</b>
    <c>
        <id>444</id>
    </c>
</top>