Retrieving null values from json using circe-optics - json

The json I have looks like this:
{
"cards": [
{
"card_id":"1234567890",
"card_status":"active",
"card_expiration":{
"formatted":"01/20"
},
"debit":{
"masked_debit_card_number":"1111 **** **** 1111",
}
},
{
"card_id":"1234567891",
"card_status":"active",
"card_expiration":null,
"debit":{
"masked_debit_card_number":"2222 **** **** 2222",
}
}
]
}
I'm trying to retrieve all card_expiration fields values using this function:
def getExpirations(json: Json) =
root
.cards
.each
.filter(root.card_status.string.exist(_ == "active"))
.card_expiration
.selectDynamic("formatted")
.string
.getAll(json)
The thing is, the above expression only returns 1 result - for the first card, but I really need to get something like List(Some("01/20"), None)! What can I do in this situation?

The issue is that by the time you've done the formatted step you're no longer matching the null expiration. You could do something like this:
import io.circe.Json, io.circe.optics.JsonPath.root
def getExpirations(json: Json) =
root
.cards
.each
.filter(root.card_status.string.exist(_ == "active"))
.card_expiration
.as[Option[Map[String, String]]]
.getAll(json)
Or:
import io.circe.Json, io.circe.generic.auto._, io.circe.optics.JsonPath.root
case class Expiration(formatted: String)
def getExpirations(json: Json) =
root
.cards
.each
.filter(root.card_status.string.exist(_ == "active"))
.card_expiration
.as[Option[Expiration]]
.getAll(json)
And then:
scala> getExpirations(io.circe.jawn.parse(doc).right.get)
res0: List[Option[Expiration]] = List(Some(Expiration(01/20)), None)
Without more context, it's not clear in my view that this is a good use case for circe-optics. You're probably better off decoding into case classes, or maybe using cursors. If you can provide more information it'd be easier to tell.

Related

getUpstreamRun from JSONArray obtained from Build causes

I am trying getUpstreamRun() in order to get Run object.
def causes = currentBuild.getBuildCauses()
// List<Cause.UpstreamCause> upstreamCauses = currentBuild.getBuildCauses('hudson.model.Cause$UpstreamCause')
def upstreamCauses = currentBuild.getBuildCauses('hudson.model.Cause$UpstreamCause')
for (Cause cause : upstreamCauses) {
echo "currentCause: ${cause}"
if (cause instanceof Cause.UpstreamCause) {
Cause.UpstreamCause upstreamCause = (Cause.UpstreamCause)cause;
Run<?, ?> upstreamRun = upstreamCause.getUpstreamRun();
if (upstreamRun != null) {
def env = upstreamRun.getEnvironment(TaskListener.NULL)
println env
}
}
}
It's failing (if condition is not satisfied) at if (cause instanceof Cause.UpstreamCause) unable to reach getUpstreamRun() function call. Looks like i am missing some kind of type casting
varible upstreamCauses looks like this and is of type "net.sf.json.JSONArray"
[[_class:hudson.model.Cause$UpstreamCause,
shortDescription:Started by upstream project "mod_production-controller-
g5/v1.0_handler_mod_production-controller-g5" build number 7,
upstreamBuild:7,
upstreamProject:mod_production-controller-g5/v1.0_handler_mod_production-controller-g5,
upstreamUrl:job/mod_production-controller-g5/job/v1.0_handler_mod_production-controller-g5/
]]
currentCause
[_class:hudson.model.Cause$UpstreamCause,
shortDescription:Started by upstream project "mod_production-controller-
g5/v1.0_handler_mod_production-controller-g5" build number 7,
upstreamBuild:7,
upstreamProject:mod_production-controller-g5/v1.0_handler_mod_production-controller-g5,
upstreamUrl:job/mod_production-controller-g5/job/v1.0_handler_mod_production-controller-g5/
]
Note how to convert this JsonArray to appropriate format to obtain run item. Any help is greatly appreciated.
If currentCause is an array, you may want to extract its first member:
Cause.UpstreamCause upstreamCause = (Cause.UpstreamCause)(cause[0])

How can i convert None field from case class to JSON correctly

I have this case class
case class Example(
exId: String,
exDes: Option[String] = None)
and I try to convert
Example(exId = 1)
to JSON (example.asJson from io.circe) I actually got
{
"exId" : "1"
"exDes": null
}
But i expected
{
"exId" : "1"
}
is there anyway to convert like i expected with io.circe ?
Just use dropNullValues, as it Scala Docs states:
Drop the entries with a null value if this is an object.
Your example looks then:
Example(exId = "1").asJson.dropNullValues
And the result is as you wanted:
{
"exId" : "1"
}

(Python)How to process complicated json data

//Please excuse my poor English.
Hello everyone, I am doing a project which is about a facebook comment spider.
then I find the Facebook Graph GUI. It will return a json file that's so complicated for me.
The json file is include so many parts
then I use json.loads to get all the json code
finally it return a dict for me.
and i dont know how to access the Value
for example i want get all the id or comment.
but i can only get the 2 key of dict "data" and "pading"
so, how can i get the next key? like "id" or "comment"
and how to process this complicated data.
code
Thank you very much.
Two ways I can think of, either you know what you're looking for and access it directly or you loop over the keys, look at the value of the keys and nest another loop until you reach the end of the tree.
You can do this using a self-calling function and with the appropriate usage of jQuery.
Here is an example:
function get_the_stuff(url)
{
$.getJSON(url, function ( data ) {
my_parser(data) });
}
function my_parser(node)
{
$.each(node, function(key, val) {
if ( val && typeof val == "object" ) { my_parser(val); }
else { console.log("key="+key+", val="+val); }
});
}
I omitted all the error checking. Also make sure the typeof check is appropriate. You might need some other elseif's to maybe treat numbers, strings, null or booleans in different ways. This is just an example.
EDIT: I might have slightly missed that the topic said "Python"... sorry. Feel free to translate to python, same principles apply.
EDIT2: Now lets' try in Python. I'm assuming your JSON is already imported into a variable.
def my_parser(node, depth=0):
if type(node) == "list":
for val in node:
my_parser(val,depth+1)
elif type(node) == "dict":
for key in node:
printf("level=%i key=%s" % ( depth, key ))
my_parser(node[key], depth+1)
elif type(node) == "str":
pritnf("level=%i value=%s" % ( depth, node ))
elsif type(node) == "int":
printf("level=%i value=%i % ( depth, node ))
else:
printf("level=%i value_unknown_type" % ( depth ))

How to handle None values in JSON

I have some code that builds a JSON object in Scala in the Playframework context
def toJson(): JsObject = Json.obj(
"status" -> JsString(result.getOrElse("fail")),
"age" -> JsNumber(age.getOrElse(0))
)
Where result and age are wrapped in an Option. The getOrElse part in the age line indicates age is not available. That's what I would like to get around.
The resulting output is:
{
status: "fail",
age: 0
}
Question A: In the example, age is None so getOrElse returns a 0 which would have to be interpreted by the clients as some magic number with special meaning. I would like to return something like None but the play.api.libs.json.JsNumber expects a scala.BigDecimal.
Is there a way to get around this somehow?
Question B: A solution to Question A would be to leave out the age in case it is not available so the result looks like:
{
status: "fail"
}
I cannot mess around within the Json.obj(a, b, ...) construct...
So how would the code look like to achieve something like this?
See if something like this works for you:
val fields:Seq[Option[(String,JsValueWrapper)]] = Seq(
result.map(s => ("status", JsString(s))),
age.map(i => ("age", JsNumber(new BigDecimal(i))))
)
val finalFields = fields.flatten
Json.obj(finalFields:_*)
When the Seq gets flattened, the None types in it should be removed and thus will not be part of the resulting JsObject.

Comparing a JsonArray with a Enumeration

I(scala beginner) was searching, but i couldn't find a fitting way to solve this following problem.
The Enumeration object(never changes):
object EyeColorEnum extends Enumeration{
val Blue = Value("blue")
val Brown = Value("brown")
val Gray = Value("gray")
val Green = Value("green")
}
The Json Array(case1):
"eyeColor": ["blue", "gray", "green"]
The Json Array(case2):
"eyeColor": []
The Json Array(case3):
"eyeColor": ["orange", "pink", "green"]
This solution should be a json validation for the field "eyeColor".
Case1 and case 2 are valid.
Case 3 is invalid.
for (i <- 1 to(jsonArray.value.length - 1)) {
for (j <- 1 to(jsonArray.value.length - 1)) {
if(jsonArray(i).as[String] == enumArray(j).toString) {
// Item from A exists in B
true
} else {
// Item from A does not exist in B
checker = checker + 1
}
}
}
These for are not working how i want them to work.
Is there probably a way more easy way to get this job done?
Thank u very much.
The reason why that is not working is that for comprehensions used in this way are doing .foreach calls against the Range instance you've created in the parens (which returns Unit rather than the value you're attempting to return):
(1 to (jsonArray.value.length - 1)).foreach{i => ...}
It sounds like you want a combination of the forall and exists methods that collections in Scala provide.
Is there somebody who could point out how to avoid the var?
This is my ugly solution:
def apply(enum: Enumeration, jsonArray: JsArray): Boolean = {
val enumArray = enum.values.toArray
var found = 0
jsonArray.value.length match {
case 0 => true
case _ =>
(0 to (jsonArray.value.length - 1)).foreach{i =>
(0 to (enumArray.length - 1)).foreach{j =>
if (jsonArray(i).as[String] == enumArray(j).toString) {
found +=1
}
}
}
found == jsonArray.value.length
}
}