在Scala中,如何使用transformer/Rewrite规则将递增ID放入XML元素中

在Scala中,如何使用transformer/Rewrite规则将递增ID放入XML元素中,xml,scala,scala-xml,Xml,Scala,Scala Xml,我想读入一个XML文件,并在特定元素中放入一个递增的id。下面是我编写的一些测试代码,以了解如何做到这一点: import scala.xml._ import scala.xml.transform._ val testXML = <document> <authors> <author> <first-name>Firstname</first-name> <last-n

我想读入一个XML文件,并在特定元素中放入一个递增的id。下面是我编写的一些测试代码,以了解如何做到这一点:

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

val testXML =
 <document>
    <authors>
      <author>
        <first-name>Firstname</first-name>
        <last-name>Lastname</last-name>
      </author>
    </authors>
 </document>


def addIDs(node : Node) : Node = {

    object addIDs extends RewriteRule {
      var authorID = -1
      var emailID = -1
      var instID = -1

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

          case Elem(prefix, "author", attribs, scope, _*) =>
            //println("element author: " + elem.text)
            if ((elem \ "@id").isEmpty) {
              println("element id is empty:" + elem\"@id")
              authorID += 1
              println("authorID is " + authorID)
              elem.asInstanceOf[Elem] % Attribute(None, "id", Text(authorID.toString), Null)
            } else {
              elem
            }


        case Elem(prefix, "email", attribs, scope, _*) =>
          println("EMAIL")
          elem.asInstanceOf[Elem] % Attribute(None, "id", Text(authorID.toString), Null)

        case Elem(prefix, "institution", attribs, scope, _*) =>
          println("INST")
          elem.asInstanceOf[Elem] % Attribute(None, "id", Text(instID.toString), Null)

        case other =>
          other
      }
    }
  }
  object transform extends RuleTransformer(addIDs)
  transform(node)
}


val newXML = addIDs(testXML)
导入scala.xml_
导入scala.xml.transform_
val testXML=
名字
姓氏
def addIDs(节点:节点):节点={
对象添加扩展了重写规则{
var authorID=-1
var emailID=-1
var institd=-1
覆盖def变换(元素:节点):Seq[节点]=
{
元素匹配{
案例元素(前缀“作者”,属性,范围,*)=>
//println(“元素作者:+elem.text”)
if((elem\“@id”).isEmpty){
println(“元素id为空:“+elem\”@id”)
authorID+=1
println(“authord是”+authord)
元素asInstanceOf[elem]%属性(无,“id”,文本(authorID.toString),Null)
}否则{
元素
}
案例元素(前缀“电子邮件”、属性、范围,*)=>
println(“电子邮件”)
元素asInstanceOf[elem]%属性(无,“id”,文本(authorID.toString),Null)
案例要素(前缀“机构”、属性、范围等)=>
println(“INST”)
元素asInstanceOf[elem]%属性(无,“id”,文本(Instit.toString),Null)
案例其他=>
其他
}
}
}
对象变换扩展规则转换器(addIDs)
变换(节点)
}
val newXML=addIDs(testXML)
此代码是功能性的-但是,ID没有按预期显示:

element id is empty:
authorID is 0
element id is empty:
authorID is 1
element id is empty:
authorID is 2
element id is empty:
authorID is 3
element id is empty:
authorID is 4
element id is empty:
authorID is 5
element id is empty:
authorID is 6
element id is empty:
authorID is 7
newXML:scala.xml.Node=<document>
    <authors>
        <author id="7">
           <first-name>Firstname</first-name>
           <last-name>Lastname</last-name>
        </author>
    </authors>
  </document>
元素id为空:
authorID为0
元素id为空:
authorID是1
元素id为空:
作者是2
元素id为空:
作者是3
元素id为空:
作者是4
元素id为空:
作者是5岁
元素id为空:
作者是6岁
元素id为空:
作者7岁
newXML:scala.xml.Node=
名字
姓氏
看起来转换器多次命中每个节点,增加id,然后在id达到7时停止。为什么在最终完成之前它会多次接触节点?我是否可以做一些不同的事情来告诉它完成该节点

我认为它可能正在遍历新修改的节点,因此我检查了包含名为“id”的属性的元素。但这似乎不起作用。也许一开始这样做是个坏主意


谢谢你在这方面的帮助

看起来我遇到了这个scala bug:-BasicTransformer具有指数级的复杂性


我的解决方法是这样做的:

当你编辑一个元素时,似乎转换的东西会更多地递归。我看了一会儿这个问题就解决不了了。相反,使用这种技术,效果很好,而且一开始似乎更有效。我发现了这个错误: