Как добавить тег XML или нет, в зависимости от опции в Scala? - PullRequest
6 голосов
/ 09 марта 2011

Относится к Добавление атрибута 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>

Я хочу сгенерировать много тегов в зависимости от опции, мне было интересно, можно ли найти более краткое решение. Например, сводить класс Elem с помощью? используйте оператор следующим образом (это грязное решение, поскольку значение Option2 преобразуется в строку перед вызовом оператора?):

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

Есть мысли?

Ответы [ 4 ]

12 голосов
/ 10 марта 2011

Ваша желаемая ? функция может быть реализована так:

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

Для простоты, это только для одиночных узлов, чтобы показать вам концепцию (я думаю, вы сможете написать более общую функцию оттуда, если она вам понадобится)

Если неявная функция находится в области видимости, оператор ? может использоваться точно так же, как вы хотели:

<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 голосов
/ 09 марта 2011

Почему бы не использовать оператор if, подобный этому:

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

Это должно сработать, и это вполне понятно, верно?

3 голосов
/ 05 октября 2015

Вы также можете fold опция:

{ value2.fold(NodeSeq.Empty)(x => <tag2>{x}</tag2>) }
2 голосов
/ 23 марта 2017

Вот простая версия, в которой не используется (возможно вводящий в заблуждение, поскольку ничего не накапливается) метод сгиба:

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

Результат тот же, что и у Золтана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...