2

Scalaインタープリターからの次のことを考慮してください。

scala> JSON.parseFull("""{"name":"jack","greeting":"hello world"}""")
res6: Option[Any] = Some(Map(name -> jack, greeting -> hello world))

マップがSome()で返されるのはなぜですか?そして、どうすればそれを扱うことができますか?

値をxmlテンプレートに入れたい:

<test>
  <name>name goes here</name>
  <greeting>greeting goes here</greeting>
</test>

マップをSome(thing)から取得し、それらの値をxmlで取得するScalaの方法は何ですか?

4

4 に答える 4

6

Option入力に応じて戻り値が異なる可能性があるため、 が返されるかparseFull、入力の解析にまったく失敗する可能性があります ( を与えるNone)。そのため、Mapキーを値に関連付けるオプションは別Listとして、JSON 文字列が配列を示している場合はオプションも返すことができます。

例:

scala> import scala.util.parsing.json.JSON._
import scala.util.parsing.json.JSON._

scala> parseFull("""{"name":"jack"}""")
res4: Option[Any] = Some(Map(name -> jack))

scala> parseFull("""[ 100, 200, 300 ]""")
res6: Option[Any] = Some(List(100.0, 200.0, 300.0))

次のように、目的を達成するためにパターン マッチングが必要になる場合があります。

scala> parseFull("""{"name":"jack","greeting":"hello world"}""") match {
     |   case Some(m) => Console println ("Got a map: " + m)
     |   case _ =>
     | }
Got a map: Map(name -> jack, greeting -> hello world)

ここで、XML 出力を生成する場合は、上記を使用してキーと値のペアを反復処理できます。

import scala.xml.XML

parseFull("""{"name":"jack","greeting":"hello world"}""") match {
  case Some(m: Map[_,_]) =>
    <test>
      {
        m map { case (k,v) =>
          XML.loadString("<%s>%s</%s>".format(k,v,k))
        }
      }
    </test>

  case _ =>
}
于 2012-02-15T08:30:31.050 に答える
6

おそらく次のようなものを使用する必要があります。

res6 collect { case x: Map[String, String] => renderXml(x) }

どこ:

def renderXml(m: Map[String, String]) = 
  <test><name>{m.get("name") getOrElse ""}</name></test>

collectメソッド onは and をOption[A]取り、(述語による) と(関数による)PartialFunction[A, B]の組み合わせです。あれは:filtermap

opt collect pf
opt filter (a => pf isDefinedAt a) map (a => pf(a))

どちらも同等です。オプションの値がある場合はmapflatMapfilter、などを使用してプログラム内のオプションを変換し、パターン マッチまたはメソッドを介してオプションの内容を抽出collectすることを回避する必要があります。絶対に使用しないでください。これは、間違っていることを示す標準的な兆候です。パターンマッチングはプログラムのフォークを表し、循環的な複雑さを増すため、避けるべきです - これをしたいのはパフォーマンスのためだけかもしれませんgetOption.get


実際には、parseJSONメソッドの結果が であるという問題がありますOption[Any](その理由はOption、おそらく、解析が成功しない可能性がありOption、より適切な処理方法であるためですnull) null

しかし、上記の私のコードの問題は、case x: Map[String, String]型消去のために実行時に をチェックできないことです (つまり、scala はオプションに aMapが含まれていることをチェックできますが、Map型パラメーターが bothであることはチェックStringできません。コードはunchecked警告を受け取ります。

于 2012-02-15T08:03:47.230 に答える
5

parseFullは、文字列が有効な JSON ではない可能性があるため、 を返しOptionます (その場合、None代わりにが返されますSome)。

a から値を取得する通常の方法は、次のSomeようにそれに対してパターン マッチを行うことです。

result match {
    case Some(map) =>
        doSomethingWith(map)
    case None =>
        handleTheError()
}

入力が常に有効であり、無効な入力のケースを処理する必要がないことが確実な場合は、 でgetメソッドを使用できますOption。これは、 で呼び出されたときに例外をスローしNoneます。

于 2012-02-15T08:02:03.763 に答える
4

2つの別々の問題があります。

  1. と入力しAnyます。
  2. データはとの中にOptionありMapます。

データがあるとしましょう:

val x: Option[Any] = Some(Map("name" -> "jack", "greeting" -> "hi"))

そして、返すものがある場合は適切なXMLを返したいが、そうでない場合は返したくないとします。次にcollect、処理方法を知っている部分を収集するために使用できます。

val y = x collect {
  case m: Map[_,_] => m collect {
    case (key: String, value: String) => key -> value
  }
}

(マップ内の各エントリをどのように分解して、文字列を文字列にマップするかを確認しました。それ以外の方法はわかりません。次のようになります。

y: Option[scala.collection.immutable.Map[String,String]] =
  Some(Map(name -> jack, greeting -> hi))

さて、それは良いです!これで、XMLに必要なフィールドがわかっている場合は、それらを要求できます。

val z = for (m <- y; name <- m.get("name"); greet <- m.get("greeting")) yield {
  <test><name>{name}</name><greeting>{greet}</greeting></test>
}

この(成功した)場合、

z: Option[scala.xml.Elem] =
  Some(<test><name>jack</name><greeting>hi</greeting></test>)

失敗した場合は、を生成しNoneます。

代わりに、マップで見つけたものをフォームでラップしたい場合は、<key>value</key>Scalaにはタグの適切な抽象化がないため、少し手間がかかります。

val z = for (m <- y) yield <test>{ m.map { case (tag, text) => xml.Elem(null, tag, xml.Null, xml.TopScope, xml.Text(text)) }}</test>

これもまた生成します

z: Option[scala.xml.Elem] =
  Some(<test><name>jack</name><greeting>hi</greeting></test>)

(を使用getしての内容を取得できますが、が空の場合(つまり) Option、例外がスローされます。)OptionNone

于 2012-02-15T12:14:35.363 に答える