1

アプリに構文的に正しくない JSON が入力された場合、問題のある領域を特定できるようにするための有用な詳細を使用して、ユーザーにエラーを報告できるようにしたいと考えています。

したがって、この例では、「File1」の後のコンマが続くため、j は None になります。最後の解析エラーの詳細を取得する方法はありますか?

    val badSyntax = """
{
  "menu1": {
    "id": "file1",
    "value": "File1",
  },
  "menu2": {
    "id": "file2",
    "value": "File2",
  }
}"""

    val j = JSON.parseFull(badSyntax)
4

1 に答える 1

2

解析エラーが発生した場合はJSON.lastNoSuccess、最後のエラーを取得するために使用します。JSON.NoSuccessこれは、 2 つのサブクラスおよびのタイプでJSON.ErrorありJSON.Failure、両方ともmsg: Stringエラーの詳細を示すメンバーを含んでいます。これJSON.lastNoSuccessはスレッドセーフではなく (単なるグローバル変数です)、現在は推奨されていません (scala 2.11 では消える予定です)。

UPDATE :どうやら、スレッドセーフではないという点で間違っていたようです。実際、scala 2.10 より前はスレッドセーフではありませんでしたが、現在lastNoSuccessはスレッドローカル変数によってサポートされています (したがって、マルチスレッドコンテキストで安全に使用できます)。 . これを見た後、解析に使用されたスレッド ( を呼び出したスレッド)と同じスレッドで解析が失敗した直後に読む限りparseFull、すべてが期待どおりに機能すると考えることができます。 . 残念ながら、このリファクタリングlastNoSuccess中に、内部での使用方法も変更されParsers.phraseました (これは によって呼び出されますJSON.parseFulllastNoSuccessNoneParsers.phrase. lastNoSuccessとにかくの結果として返される一時的な値として使用されるため、これは一般的なパーサーでは問題ありませParsers.phraseん。 ここでの問題は、 を呼び出さずに を呼び出しParsers.phraseJSON.parseFullエラー情報をドロップすることです( https://github.com/scala/scala/blob/v2.10.0/src/library/scala/util/parsingcase None => Noneの内部メソッドJSON.parseRawを参照してください)。 /json/JSON.scala )。scala 2.10 より前のバージョンでは、エラー情報をドロップするという事実は、以前にアドバイスしたように、JSON.parseFull直接読み取ることで簡単に回避できましJSON.lastNoSuccessたが、この値は の最後でリセットされるParsers.phraseため、 からエラー情報を取得するためにできることはあまりありませんJSON

解決策はありますか?はい。できることはJSON、エラー情報を削除しない独自のバージョンを作成することです。

import util.parsing.json._

object MyJSON extends Parser {
  def parseRaw(input : String) : Either[NoSuccess, JSONType] = {
    phrase(root)(new lexical.Scanner(input)) match {
      case Success(result, _) => Right(result)
      case ns: NoSuccess => Left(ns)
    }
  }

  def parseFull(input: String): Either[NoSuccess, Any] = {
    parseRaw(input).right.map(resolveType)
  }

  def resolveType(input: Any): Any = input match {
    case JSONObject(data) => data.transform {
      case (k,v) => resolveType(v)
    }
    case JSONArray(data) => data.map(resolveType)
    case x => x
  }
}

結果の型を に変更OptionしただけEitherなので、解析エラーをLeft. REPL でのいくつかのテスト:

scala> MyJSON.parseFull("[1,2,3]")
res11: Either[MyJSON.NoSuccess,Any] = Right(List(1.0, 2.0, 3.0))

scala> MyJSON.parseFull("[1,2,3")
res12: Either[MyJSON.NoSuccess,Any] =
Left([1.7] failure: end of input

[1,2,3
      ^)
于 2013-02-05T22:50:41.330 に答える