In Scala, how can I put an incremental id in an XML element using the transformer / Rewrite rule

I want to read in an XML file and put an incremental id on certain elements. Here are some test codes I wrote to figure out how to do it:

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)

      

This code is functional - but ids don't come out as expected:

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>

      

it looks like the transformer hits each node multiple times, incrementing the id and then finally stopping when id reaches 7. Why did it touch the node so much before finally ending up with it? Is there something I could do differently to tell him to finish with this node?

I thought it might have stepped over the recently changed node, so my check is for an element containing an attribute named 'id'. But it doesn't work. Maybe it's a bad idea to do it in the first place?

Thanks for any help on this.

+3


source to share


1 answer


Looks like I hit this scala bug: https://issues.scala-lang.org/browse/SI-3689 - BasicTransformer has exponential complexity



My workaround was to do this: fooobar.com/questions/153011 / ...

0


source







All Articles