xml - Scala - 修改 xml 中的嵌套元素

标签 xml scala

我正在学习 Scala,并且希望更新某些 XML 中的嵌套节点。我有一些工作,但我想知道它是否是最优雅的方式。

我有一些 xml:

val InputXml : Node =
<root>
    <subnode>
        <version>1</version>
    </subnode>
    <contents>
        <version>1</version>
    </contents>
</root>

我想更新子节点中的版本节点,而不是内容中的节点。

这是我的功能:

def updateVersion( node : Node ) : Node = 
 {
   def updateElements( seq : Seq[Node]) : Seq[Node] = 
   {
        var subElements = for( subNode <- seq ) yield
        {
            updateVersion( subNode )
        }   
        subElements
   }

   node match
   {
     case <root>{ ch @ _* }</root> =>
     {
        <root>{ updateElements( ch ) }</root>
     }
     case <subnode>{ ch @ _* }</subnode> =>
     {
         <subnode>{ updateElements( ch ) }</subnode> 
     }
     case <version>{ contents }</version> =>
     {
        <version>2</version>
     }
     case other @ _ => 
     {
         other
     }
   }
 }

这个函数有没有更简洁的写法?

最佳答案

一直以来,没有人真正给出最合适的答案!不过,现在我已经了解了它,这是我对它的新看法:

import scala.xml._
import scala.xml.transform._

object t1 extends RewriteRule {
  override def transform(n: Node): Seq[Node] = n match {
    case Elem(prefix, "version", attribs, scope, _*)  =>
      Elem(prefix, "version", attribs, scope, Text("2"))
    case other => other
  }
}

object rt1 extends RuleTransformer(t1)

object t2 extends RewriteRule {
  override def transform(n: Node): Seq[Node] = n match {
    case sn @ Elem(_, "subnode", _, _, _*) => rt1(sn)
    case other => other
  }
}

object rt2 extends RuleTransformer(t2)

rt2(InputXml)

现在,进行一些解释。 RewriteRule 类是抽象类。它定义了两个方法,都称为 transform。其中一个采用单个 Node,另一个采用 NodeSequence。它是一个抽象类,所以我们不能直接实例化它。通过添加一个定义,在本例中覆盖了其中一个 transform 方法,我们正在创建它的一个匿名子类。每个 RewriteRule 需要关注一个任务,尽管它可以做很多。

接下来,RuleTransformer 类将可变数量的 RewriteRule 作为参数。它的转换方法采用 Node 并返回 NodeSequence,通过应用每个用于实例化的 RewriteRule

这两个类都派生自 BasicTransformer,它定义了一些不需要在更高层次上关注的方法。不过,它是 apply 方法调用 transform,因此 RuleTransformerRewriteRule 都可以使用与其关联的语法糖。例子中前者有,后者没有。

这里我们使用两级 RuleTransformer,第一级将过滤器应用于更高级别的节点,第二级将更改应用于通过过滤器的任何内容。

同样使用提取器Elem,这样就不用关心命名空间,有没有属性等细节了。并不是说元素 version 的内容被完全丢弃并替换为 2。如果需要,它也可以匹配。

另请注意,提取器的最后一个参数是_*,而不是_。这意味着这些元素可以有多个子元素。如果您忘记了 *,匹配可能会失败。在示例中,如果没有空格,匹配不会失败。因为空格被翻译成 Text 元素,所以 subnode 下的单个空格会导致匹配失败。

此代码比其他建议大,但它的优点是对 XML 结构的了解比其他建议少得多。它会更改任何名为 version 的元素,无论有多少层 - 一个名为 subnode 的元素,无论 namespace 、属性等。

此外...好吧,如果你有很多转换要做,递归模式匹配很快就会变得不屈服。使用 RewriteRuleRuleTransformer,您可以有效地将 xslt 文件替换为 Scala 代码。

关于xml - Scala - 修改 xml 中的嵌套元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/970675/

相关文章:

java - 使用 JAXB 解码将 XML 转换为 Java

regex - Sublime Text xml替换正则表达式结果

scala - 序列化问题 "scala.math.BigDecimal does not have a no-arg default constructor"

scala - BodyParser 根据请求体返回结果

c# - 将 XML 父节点插入现有 xml 文档

xml - MATLAB:修改XML文件并保存

scala - "Higher Kinded Type Should be Enabled"警告

具有多个键的 Java WeakHashMap?

java - Scala + JDBC = 编译后找不到驱动程序

xml - 有效的 XML 文件是否需要 XML 声明?