在Scala宏中匹配XML文字

Mar*_*ing 8 scala scala-xml scala-macros scala-quasiquotes

我想用宏转换Scala XML文字.(不是带XML的字符串文字,而是实际的XML文字).据我所知,XML文字实际上并没有构建在AST级别的语言中,而是在解析器中被贬低.有趣的是,这确实有效:

case q"<specificTag></specificTag>" => ... // succeeds for specificTag with no
                                           // attributes and children
Run Code Online (Sandbox Code Playgroud)

但显然,这完全没用,因为不可能以任意方式匹配任意xml.就像是

case q"<$prefix:$label ..$attrs>$children</$prefix:$label>" => ...
Run Code Online (Sandbox Code Playgroud)

无法工作,因为我们必须在模式中绑定相同的变量两次.

打印出这样的xml文字表达式的树实际上给出了desugared版本.例如.

new _root_.scala.xml.Elem(null,"specificTag",_root_.scala.xml.Null,$scope,false)
Run Code Online (Sandbox Code Playgroud)

但尝试匹配此失败:

case q"new _root_.scala.xml.Elem(..$params)" => ... // never succeeds
Run Code Online (Sandbox Code Playgroud)

我很迷惑!我的问题是:有没有办法可靠地匹配scala宏中的任意xml litarals?另外:为什么它们在quasiquotes中支持常量xml而不是desugared值呢?

som*_*ytt 2

xml 被包装在块中,宏被调用为rename( <top><bottom>hello</bottom></top> ). 我注意到,通过查看传入的树,而不是由准引号构建的树。

我之前看你的问题时就提出过这个问题;我不知道我的SO是不是这样;我试着撞上SSsbt。还有另一个可能不相关的问题。

  class Normalizer(val c: Context) {
    import c.universe._ 
    def impl(e: c.Tree) = e match {
      case Block(List(), Block(List(), x)) => x match {
        case q"new scala.xml.Elem($prefix, $label, $attrs, $scope, $min, $t)" =>
          Console println s"Childed tree is ${showRaw(e)}" 
          val b = t match {
            case Typed(b, z) => c.untypecheck(b.duplicate)
            case _           => EmptyTree
          } 
          val Literal(Constant(tag: String)) = label
          val x = c.eval(c.Expr[NodeBuffer](b))
          //q"""<${tag.reverse}>..$x</${tag.reverse}>"""  // SO
          e
        case q"new scala.xml.Elem($prefix, $label, $attrs, $scope, $min)" =>
          Console println s"Childless tree is ${showRaw(e)}" ; e
        case _ => Console println s"Tree is ${showRaw(e)}" ; e
      }
      case _ => Console println s"Nonblock is ${showRaw(e)}" ; e
    }
  }
Run Code Online (Sandbox Code Playgroud)