3

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

例如config是scala Map,我想如下使用它,但实际上以下不起作用。谁能帮助我?谢谢

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

2 回答 2

1

可惜你写不出你想要的东西。我猜 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将接受 aString作为属性值。

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元素以便NodeSeqAttribute.

于 2017-05-04T21:03:00.523 回答
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
)
于 2017-05-03T15:17:31.080 回答