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

Mar*_*ela 6 xml scala

根据选项添加XML属性相关,我想根据选项在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
Run Code Online (Sandbox Code Playgroud)

如果选项存在:

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

如果选项不存在:

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

</body>
Run Code Online (Sandbox Code Playgroud)

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

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

有什么想法吗?

Mar*_*ing 12

?可以通过以下方式实现所需的功能:

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
    }      
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

<body>
{ <tag1>{ Some("Hello") }</tag1>?  }
{ <tag2>{ None }</tag2>? }
{ <tag3>{ Some(<innerTag/>) }</tag3>? }
{ <tag4><innerTag/></tag4>? }
{ <tag5>{ None }</tag5>? }
</body>
Run Code Online (Sandbox Code Playgroud)

将导致:

<body>
  <tag1>Hello</tag1>

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

</body>
Run Code Online (Sandbox Code Playgroud)


小智 7

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

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

这应该是诀窍而且是可以理解的,对吧?


Zol*_*tán 5

您还可以fold选择:

{ value2.fold(NodeSeq.Empty)(x => <tag2>{x}</tag2>) }
Run Code Online (Sandbox Code Playgroud)