开发者

substituting xml values programmatically with scala

开发者 https://www.devze.com 2023-01-21 17:45 出处:网络
I\'m writing a tool to update some xml files (pom.xml in this case) with scala because the effort it would take in java is significantly higher than (in theory) it is with scala. I can parse the xml f

I'm writing a tool to update some xml files (pom.xml in this case) with scala because the effort it would take in java is significantly higher than (in theory) it is with scala. I can parse the xml file just fine, but I need to replace nodes in the existing xml and rewrite the result. for example:

<dependency>
    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0-S开发者_如何学CNAPSHOT</version>
</dependency>

So I want to find all nodes like this and replace them with:

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

So, I can get all the version nodes simply enough, but how to replace them with the node that I want?

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

then I want to do something like:

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

which doesn't work because node is immutable. I looked at the copy method for a Node, but it doesn't include text as a parameter.


You really should take a look at other questions on Stack Overflow about modifying XML. Look at the "Related" links to the right.

Here:

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>


Text is represented as a Node inside of the Elements Node. So a bit of functional recursion will let you do a deep copy & filter:

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
}

disclaimer: this code was not tested for errors


Using Scalate's Scuery CSS3 transforms and scala.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)

yields

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号