2011-03-08 55 views
6

Adding an XML attribute depending on an Option相关,我想根据一个选项在Scala中添加一个XML标签。如何添加XML标签,取决于Scala中的选项?

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> 

我要产生大量的根据选项标签,我想知道是否可以找到更简洁的解决方案。举例来说,用Elemental类来拉扯Elem类?运营商和使用它像这样(?这是因为选项的值2肮脏的溶液转化为前一个字符串操作叫做):

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

有什么想法?

回答

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> 
6

为什么不是,如果这样的语句中使用:

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

这应该做的伎俩,是相当可以理解的,对不对?

+1

感谢安妮的回答,这更清楚地表明我对地图的使用和拼合。不过,我想避免复制和粘贴每个选项的定义测试。我正在寻找一个代码看起来几乎像XML输出的解决方案。 – 2011-03-09 18:56:42

3

fold可以选择:

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

这比其他答案更简单。 – Casey 2017-03-14 19:09:08

2

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

value2.map(x => <tag2>{x}</tag>).getOrElse(NodeSeq.Empty) 

结果和佐尔坦的答案一样。