如何通过Scala中的Map创建动态的xml属性

时间:2017-05-03 05:23:19

标签: scala scala-xml

我有一个包含一些属性的Map,我想创建一个具有这些属性的xml元素。

e.g。 config是scala Map,我想将它用作以下内容,但实际上以下内容不起作用。谁能帮助我?感谢

<input type="text" {config.map(entry => entry._1 + "=" + entry._2)}></input>

2 个答案:

答案 0 :(得分:1)

使用低级API。这是scalac解析器在解除你的xml文字时生成的内容:

import scala.xml.{UnprefixedAttribute, MetaData, TopScope, Text, Elem, Null}

val config: Map[String, String] = Map("k1" -> "v2", "k2" -> "v2")

val seed: MetaData = Null // Don't ask.
val meta: MetaData = config.toList.foldLeft(seed) {
  case (acc, (s1, s2)) =>
    new UnprefixedAttribute(
      key   = s1,
      value = s2,
      next  = acc
    )
}

Elem(
  prefix        = null,
  label         = "input",
  attributes    = meta,
  scope         = TopScope,
  minimizeEmpty = false
)

答案 1 :(得分:1)

Bummer你无法写出你想要的东西。我猜Scala编译器的XML文字解析器不够复杂,只能用在任何地方插入的表达式来解析XML文字。它们只能位于标签之间或作为单独的属性值。

作为一种解决方法,可以创建没有属性的元素,或只创建一个属性,其余属性丢失:

val elem = <input type="text"/>

然后,您可以使用几个复制构造函数添加Map中的属性。

elem.copy(
  attributes = elem.attributes.copy(
    config.foldLeft(scala.xml.Null: scala.xml.MetaData) {
      case (next, (k, v)) => scala.xml.Attribute(k, scala.xml.Text(v), next)
    }
))
res1: scala.xml.Elem = <input type="text" k2="v2" k1="v2"/>

以上使用Elem的复制构造函数,然后使用attributes的复制构造函数。

还可以选择只使用一个复制构造函数并稍微折叠一下:

elem.copy(attributes = config.foldRight(elem.attributes) {
  case ((k, v), next) => scala.xml.Attribute(k, scala.xml.Text(v), next)
})
res2: scala.xml.Elem = <input k1="v2" k2="v2" type="text"/>

这可能是最简单的选择。

虽然,Olivier的解决方案确实显示UnprefixedAttributed会接受String作为属性值。

elem.copy(attributes = config.foldRight(elem.attributes) {
  case ((k, v), next) => new scala.xml.UnprefixedAttribute(k, v, next)
})
res3: scala.xml.Elem = <input k1="v2" k2="v2" type="text"/>

这样可以避免必须生成Text元素,以便为NodeSeq提供Attribute值。