如何添加XML标记,具体取决于Scala中的选项?

时间:2011-03-08 22:04:50

标签: xml scala

Adding an XML attribute depending on an Option相关,我想根据选项在Scala中添加XML标记。

scala> def toXml(value1: String, value2: Option[String]) =
     | <body>
     |   <tag1>{value1}</tag1>
     |   {value2 map (x => <tag2>{x}</tag2>) flatten}
     | </body>
toXml: (value1: String,value2: Option[String])scala.xml.Elem

如果选项存在:

scala> toXml("value1", Some("value2"))
res1: scala.xml.Elem =
<body>
  <tag1>value1</tag1>
  <tag2>value2</tag2>
</body>

如果选项不存在:

scala> toXml("value1", None)
res2: scala.xml.Elem =
<body>
  <tag1>value1</tag1>

</body>

我想根据选项生成很多标签,我想知道是否可以找到更简洁的解决方案。例如,拉着Elem班的?运算符并使用它(这是一个肮脏的解决方案,因为在调用?运算符之前,Option value2被转换为String):

scala> def toXml2(value1: String, value2: Option[String]) =
     | <body>
     |   <tag1>{value1}</tag1>
     |   {<tag2>{value2}</tag2>?}
     | </body>

有什么想法吗?

4 个答案:

答案 0 :(得分:11)

您可以实现所需的?功能:

implicit def optionElem(e: Elem) = new {
  def ? : NodeSeq = {
    require(e.child.length == 1)
    e.child.head match {
      case atom: Atom[Option[_]] => atom.data match {
        case None    => NodeSeq.Empty
        case Some(x) => e.copy(child = x match {
          case n: NodeSeq => n
          case x => new Atom(x)
        })
      }
      case _ => e
    }      
  }
}

为简单起见,这仅适用于单个childed节点向您展示概念(我猜您应该能够从那里编写更通用的函数以备不时之需)

如果隐式函数在范围内,?运算符可以按照您的需要使用:

<body>
{ <tag1>{ Some("Hello") }</tag1>?  }
{ <tag2>{ None }</tag2>? }
{ <tag3>{ Some(<innerTag/>) }</tag3>? }
{ <tag4><innerTag/></tag4>? }
{ <tag5>{ None }</tag5>? }
</body>

将导致:

<body>
  <tag1>Hello</tag1>

  <tag3><innerTag></innerTag></tag3>
  <tag4><innerTag></innerTag></tag4>

</body>

答案 1 :(得分:6)

为什么不使用这样的if语句:

def toXml(value1:String,value2:Option[String]) =
  <body>
    <tag1>{value1}</tag1>
    {if (value2 isDefined) <tag2>{value2.get}</tag2>}
  </body>

这应该可以解决问题并且是可以理解的,对吧?

答案 2 :(得分:3)

您还可以fold选项:

{ value2.fold(NodeSeq.Empty)(x => <tag2>{x}</tag2>) }

答案 3 :(得分:2)

这是一个简单的版本,不使用(可以说是误导,因为没有积累)折叠方法:

if (!oops_flag) {
    var speed = (score===1) ? 70 : 100;
    timerID = setTimeout(dotime, speed);
}

结果与佐尔坦的答案相同。