1

次のJsonを解析してScalaオブジェクトにしようとしています:

{
  "oneOf": [    
    { "$ref": "..." },
    { "$ref": "..." },
    { "$ref": "..." }
}

フィールド「oneOf」は、「anyOf」または「allOf」の場合もあります。これらの値の 1 つだけになります。Play の JSON ライブラリを使用して、ケース クラス ComplexType を構築しています。ロジックは単純です。指定されたフィールドを探し、存在する場合はそれを読み取り、存在しない場合は別のフィールドをチェックします。

(json \ "allOf") match {
    case a:JsArray => ComplexType("object", "allOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
    case _ => 
        (json \ "anyOf") match {
            case a:JsArray => ComplexType("object", "anyOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
            case _ =>
                  (json \ "oneOf") match {
                        case a:JsArray => ComplexType("object", "oneOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
                        case _ => ComplexType("object", "oneOf", "Unspecified" :: Nil)
                      }
                  }
              } 

この構文には満足できません。動作しますが、一致するものが見つからない場合に、一致するステートメントをネストする必要がある理由がわかりません。for-comprehension はうまく機能すると思います: ガード句で (json \ "allOf")、(json \ "oneOf) などをチェックして、利用可能な結果を​​得ることができますが、正しい構文を取得する方法がわかりません。

このケース クラスを構築するよりエレガントな方法はありますか?

ありがとう、

マイク

4

1 に答える 1

2

ここでは for-comprehension は役に立たないと思います。

次のようなカスタム エクストラクタを使用して、コードを読みやすくすることができます。

class Extractor(s: String) {
  def unapply(v: JsValue): Option[JsArray] = json \ s match {
    case a: JsArray => Some(a)
    case _ => None
  }
}

val AllOf = new Extractor("allOf")
val AnyOf = new Extractor("anyOf")
val OneOf = new Extractor("oneOf")

val (name, es) = json match {
    case AllOf(a) => "allOf" -> Some(a)
    case AnyOf(a) => "anyOf" -> Some(a)
    case OneOf(a) => "oneOf" -> Some(a)
    case _ => "oneOf" -> None
  }
val result =
  es.
    map{ a => ComplexType("object", name, a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String]))) }.
    getOrElse("Unspecified" :: Nil)
于 2013-06-05T15:54:27.967 に答える