【问题标题】:substituting xml values programmatically with scala用scala以编程方式替换xml值
【发布时间】:2019-01-23 10:18:38
【问题描述】:

我正在编写一个工具来用 scala 更新一些 xml 文件(在这种情况下是 pom.xml),因为它在 java 中所花费的工作量明显高于(理论上)它在 scala 中的工作量。我可以很好地解析xml文件,但是我需要替换现有xml中的节点并重写结果。例如:

<dependency>
    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

所以我想找到所有这样的节点并将它们替换为:

<dependency>
    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0</version> <!-- notice the lack of -SNAPSHOT here -->
</dependency>

所以,我可以简单地获取所有版本节点,但是如何将它们替换为我想要的节点呢?

// document is already defined as the head of the xml file
nodes = for (node <- document \\ "version"; if (node.text.contains("SNAPSHOT"))) yeild node

然后我想做类似的事情:

for (node <- nodes) {
    node.text = node.text.split("-")(0)
}

这不起作用,因为节点是不可变的。我查看了节点的复制方法,但它不包含 text 作为参数。

【问题讨论】:

标签: xml scala


【解决方案1】:

你真的应该看看 Stack Overflow 上关于修改 XML 的其他问题。查看右侧的“相关”链接。

这里:

scala> <dependency>
     |     <groupId>foo</groupId>
     |     <artifactId>bar</artifactId>
     |     <version>1.0-SNAPSHOT</version>
     | </dependency>
res0: scala.xml.Elem =
<dependency>
    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

scala> new scala.xml.transform.RewriteRule {
     |   override def transform(n: Node): Seq[Node] = n match {
     |     case <version>{v}</version> if v.text contains "SNAPSHOT" => <version>{v.text.split("-")(0)}</version>
     |     case elem: Elem => elem copy (child = elem.child flatMap (this transform))
     |     case other => other
     |   }
     | } transform res0
res9: Seq[scala.xml.Node] =
<dependency>
    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0</version>
</dependency>

【讨论】:

  • 你知道你的解决方案在时间上的复杂性吗? XML 树中的匹配/搜索的成本是多少? O(log n)?
  • @Themerius 如果我没记错的话,它曾经是 n 的平方,深度为 n。有一张票和一个补丁,但我不记得它是否得到修复。
【解决方案2】:

文本在Elements 节点内表示为Node。因此,一些函数递归将让您进行深度复制和过滤:

def deepCopy(node:Node) : Node = node match {
  case e : Elem => e.copy(child = this.child.toSeq.map(deepCopy))
  case t : Text => new Text(t.text.split("-").head)
  case x => x
}

免责声明:此代码未经过错误测试

【讨论】:

    【解决方案3】:

    使用Scalate's Scuery CSS3 transformsscala.xml.Elem#copy

    val xml =
      <dependency>
        <version>1.0-SNAPSHOT</version>
        <version>2.0</version>
      </dependency>
    
    new Transformer {
      $("dependency > version") { node =>
        node.asInstanceOf[Elem].copy(child = Text(node.text.stripSuffix("-SNAPSHOT")))
      }
    }.apply(xml)
    

    产量

    NodeSeq(<dependency><version>1.0</version><version>2.0</version></dependency>)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-03
      • 2013-11-07
      • 2020-07-01
      • 2018-05-13
      • 2011-06-09
      相关资源
      最近更新 更多