Search code examples
xmlscalaformattingscala-xml

scala.xml.PrettyPrinter to format shorter node when there is no text in it


I use scala.xml.PrettyPrinter to format my XML in Scala. The problem is with nodes without text content. Instead of this:

<node></node>

I'd prefer to have this:

<node />

How can I make PrettyPrinter to format it my way?


Solution

  • This was a bug in scala-xml, but it was fixed in version 1.1.0 on Feb-20-2018. A new option minimizeEmpty was added to PrettyPrinter.

    To use 1.1.0, add the following to your build.sbt:

    libraryDependencies ++= Seq(
      "org.scala-lang.modules" %% "scala-xml" % "1.1.0"
    )
    

    Here's an example of how to make use of the new option in PrettyPrinter:

    val pp = new xml.PrettyPrinter(80, 2, minimizeEmpty = true)
    val x = <node><leaf></leaf></node>
    println(pp.format(x))
    

    This will output:

    <node>
      <leaf/>
    </node>
    

    If the Scala compiler, complains:

    java.lang.NoSuchMethodError: scala.xml.PrettyPrinter.<init>(IIZ)V
    

    then you need to enable a forked JVM in sbt, so that Scala is using the new version of scala-xml. Just add the follow to your build.sbt:

    fork := true
    

    Previous to scala-xml 1.1.0, the method to create <node/>, leafTag(), is in the class, but unused. You can fix it like so:

    import xml._
    val p2 = new PrettyPrinter(120, 2) {
      override protected def traverse(node:Node, pscope:NamespaceBinding, ind:Int) = 
        node match {
          case n:Elem if n.child.size == 0 => makeBox(ind, leafTag(n))
          case _ => super.traverse(node, pscope, ind)
        }
    }
    

    There's no reason to use the override-hack if you can just upgrade to 1.1.0.