简体   繁体   中英

How to match case the undeprecated apply-method of scala.xml.Elem

in order to update a child on a xml node you can do this (other SO-ticket ref missing here):

val node:Node = <item><category>1</category></item>
val root = node match {
  case Elem(p,l,a,s, child @ _*) ⇒ Elem(p,l,a,s,child.filter(_.label != "category") ++ <category>2</category>:_* )
  case _ ⇒ node // error case
}

This gives a deprecated warning, as one should use the Elem method with explicit naming of minimizeEmpty as 5th parameter:

val node:Node = <item><category>1</category></item>
val root = node match {
  case Elem(p,l,a,s,m,child @ _*) ⇒ Elem(p,l,a,s,m,child.filter(_.label != "category") ++ <category>2</category>:_* )
  case _ ⇒ node // error case
}

This however does not work, as it always applies the deconstructing of the apply method without the explicit Boolean parameter, hence m always gets the type Node and nothing fits.

So how can I help the compiler to select the correct Constructor/apply-method? (scala 2.12.1)

Not working:

case Elem(p,l,a,s,m:Boolean,child @ _*)
case Elem(p,l,a,s,m @(_:Boolean),child @ _*) 
case Elem(p,l,a,s,m @Boolean,child @ _*)

All tell me, that m must be Node

If you look at the deprecation warning, it's with the companion object's apply method, and not with the pattern match constructor:

> set scalacOptions += "-deprecation"
> console
scala> import scala.xml._

scala> val node:Elem = <item><category>1</category></item>

scala> node match {
         case Elem(p,l,a,s, child @ _*) ⇒ Elem(p,l,a,s,child.filter(_.label != "category") ++ <category>2</category>:_* )
       }
<console>:17: warning: method apply in object Elem is deprecated: Use the other apply method in this object
  case Elem(p,l,a,s, child @ _*) ⇒ Elem(p,l,a,s,child.filter(_.label != "category") ++ <category>2</category>:_* )
                                   ^

It might be useful to just use a variable-binding parameter with @ :

scala> node match {
     |   case e @ Elem(p,l,a,s, child @ _*) ⇒ Elem(p,l,a,s,e.minimizeEmpty,child.filter(_.label != "category") ++ <category>2</category>:_* )
     | }
res1: scala.xml.Elem = <item><category>2</category></item>

I'm a little surprised the pattern match for Elem has this defect. For some reason Elem was converted to a companion object with an apply method, in 2007, from a case class. In 2012, the second apply method was added and deprecated the first.

Functions in Scala support varargs, and they work well. Case classes in Scala also support varargs. In this case, this is with apply methods using varargs, and there are two of them. The compiler supports the use of multiple apply methods, but how that interacts with varargs might makes pattern matching difficult. I don't think the scala-xml maintainers understood the impact of their changes, with respect to pattern matching, when they added a second apply method to add new parameters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM