1
1
package org.globalnames.parser
2
2
package formatters
3
3
4
-
import org.json4s.JsonAST.{JArray, JNothing, JValue}
5
-
import org.json4s.JsonDSL._
6
-
import org.json4s.jackson.JsonMethods
7
-
8
-
import scalaz.syntax.bind._
9
4
import scalaz.syntax.std.boolean._
10
5
import scalaz.syntax.std.option._
11
-
import scalaz.std.option._
12
6
13
7
import spray.json._
14
8
9
+
import formatters.{JsonRenderer => jr}
10
+
11
+
object JsonRendererProtocol extends DefaultJsonProtocol {
12
+
13
+
import DetailsRendererJsonProtocol.nameFormat
14
+
15
+
implicit val canonicalNameFormat = jsonFormat3(jr.CanonicalName)
16
+
17
+
implicit val summaryFormat = jsonFormat15(jr.Summary)
18
+
19
+
}
20
+
15
21
class JsonRenderer(result: Result,
16
22
positionsRenderer: PositionsRenderer,
17
23
detailsRenderer: DetailsRenderer,
18
24
version: String) {
19
25
20
-
import DetailsRendererJsonProtocol._
21
-
22
26
private val canonicalOpt = result.canonical
23
27
24
-
private def convert(inputJson: JsValue): JValue = {
25
-
JsonMethods.parse(inputJson.compactPrint)
26
-
}
27
-
28
-
def json(showCanonicalUuid: Boolean = false): JValue = {
28
+
def json(showCanonicalUuid: Boolean = false): jr.Summary = {
29
29
val parsed = canonicalOpt.isDefined
30
30
31
-
val canonicalName: JValue =
32
-
if (parsed) {
33
-
val canonizedUuidStrOpt = canonicalOpt.map { _.id.toString }
34
-
("id" -> showCanonicalUuid.option { canonizedUuidStrOpt }.join) ~
35
-
("value" -> canonicalOpt.map { _.value }) ~
36
-
("valueRanked" -> canonicalOpt.map { _.ranked })
37
-
} else JNothing
38
-
39
-
val quality = canonicalOpt.map { _ => result.scientificName.quality }
40
-
val qualityWarnings: Option[JArray] =
41
-
if (result.warnings.isEmpty) None
42
-
else {
43
-
val warningsJArr: JArray =
44
-
result.warnings.sorted
45
-
.map { w => JArray(List(w.level, w.message)) }.distinct
46
-
warningsJArr.some
47
-
}
48
-
val positionsJson: Option[JArray] = parsed.option {
31
+
val canonicalName = result.canonical.map { can =>
32
+
jr.CanonicalName(
33
+
id = showCanonicalUuid.option { can.id.toString },
34
+
value = can.value,
35
+
valueRanked = can.ranked
36
+
)
37
+
}
38
+
39
+
val quality = parsed.option { result.scientificName.quality }
40
+
41
+
val qualityWarnings =
42
+
(!parsed || result.warnings.isEmpty) ? Option.empty[Vector[jr.WarningSummary]] |
43
+
result.warnings.sorted
44
+
.map { w => (w.level, w.message) }
45
+
.distinct
46
+
.some
47
+
48
+
val positions: Option[Seq[jr.PositionSummary]] = parsed.option {
49
49
positionsRenderer.positioned.map { position =>
50
-
JArray(List(position.nodeName,
51
-
result.preprocessorResult.verbatimPosAt(position.start),
52
-
result.preprocessorResult.verbatimPosAt(position.end)))
50
+
(position.nodeName,
51
+
result.preprocessorResult.verbatimPosAt(position.start),
52
+
result.preprocessorResult.verbatimPosAt(position.end))
53
53
}
54
54
}
55
55
56
-
val details =
57
-
detailsRenderer.details.isEmpty ?
58
-
(JNothing: JValue) |
59
-
convert(detailsRenderer.details.toJson)
60
-
61
-
JsonMethods.render(
62
-
("nameStringId" -> result.preprocessorResult.id.toString) ~
63
-
("parsed" -> parsed) ~
64
-
("quality" -> quality) ~
65
-
("qualityWarnings" -> qualityWarnings) ~
66
-
("parserVersion" -> version) ~
67
-
("verbatim" -> result.preprocessorResult.verbatim) ~
68
-
("normalized" -> result.normalized) ~
69
-
("canonicalName" -> canonicalName) ~
70
-
("hybrid" -> result.scientificName.hybrid) ~
71
-
("surrogate" -> result.scientificName.surrogate) ~
72
-
("unparsedTail" -> result.scientificName.unparsedTail) ~
73
-
("virus" -> result.preprocessorResult.virus) ~
74
-
("bacteria" -> result.scientificName.bacteria) ~
75
-
("details" -> details) ~
76
-
("positions" -> positionsJson))
56
+
val detailsSummary = {
57
+
val detailsOpt = parsed.option { detailsRenderer.details }
58
+
detailsOpt.flatMap { det => det.nonEmpty ? det.some | None }
59
+
}
60
+
61
+
jr.Summary(
62
+
nameStringId = result.preprocessorResult.id.toString,
63
+
parsed = parsed,
64
+
quality = quality,
65
+
qualityWarnings = qualityWarnings,
66
+
parserVersion = version,
67
+
verbatim = result.preprocessorResult.verbatim,
68
+
normalized = result.normalized,
69
+
canonicalName = canonicalName,
70
+
hybrid = result.scientificName.hybrid,
71
+
surrogate = result.scientificName.surrogate,
72
+
unparsedTail = result.scientificName.unparsedTail,
73
+
virus = result.preprocessorResult.virus,
74
+
bacteria = result.scientificName.bacteria,
75
+
details = detailsSummary,
76
+
positions = positions
77
+
)
77
78
}
78
79
}
80
+
81
+
object JsonRenderer {
82
+
type PositionSummary = (String, Int, Int)
83
+
type WarningSummary = (Int, String)
84
+
85
+
case class Summary(nameStringId: String,
86
+
parsed: Boolean,
87
+
quality: Option[Int],
88
+
qualityWarnings: Option[Vector[(Int, String)]],
89
+
parserVersion: String,
90
+
verbatim: String,
91
+
normalized: Option[String],
92
+
canonicalName: Option[CanonicalName],
93
+
hybrid: Option[Boolean],
94
+
surrogate: Boolean,
95
+
unparsedTail: Option[String],
96
+
virus: Boolean,
97
+
bacteria: Boolean,
98
+
details: Option[Seq[DetailsRenderer.Name]],
99
+
positions: Option[Seq[(String, Int, Int)]])
100
+
101
+
case class CanonicalName(id: Option[String],
102
+
value: String,
103
+
valueRanked: String)
104
+
}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4