How to escape "#" when reading from a JSON response? - json

Let's say I have below sample JSON response from which I want to extract value for "#type":
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"phoneNumbers": [
{
"#type" : "iPhone",
"number": "0123-4567-8888"
},
{
"#type" : "home",
"number": "0123-4567-8910"
}
]
}
Validated using:- http://jsonpath.com/
This works for "number":
$.phoneNumbers.[number]
But cannot get value for "#type":
$.phoneNumbers.[#type]
Tried multiple ways but no luck.
Thanks!
Edits:- added another value in the array for "home", now indexing logic [0,1] doesn't work. Even tried with [:] to fetch all values, but no luck.

You can read in this documentation:
Please note, that the return value of jsonPath is an array, which is
also a valid JSON structure.
So basically it always returns an array.
var phoneTypes = jsonPath(json,"$.phoneNumbers.[#type]");
result
["iPhone","home"]
if you want one phone you have to use phoneTypes[0] for iPhone
but I higly recommend you to fix your json using this code
var fixedJson= JSON.parse(JSON.stringify(json).replaceAll("\"#type\"","\"type\"" ));
in this case you can use the real search
var homePhone = jsonPath(fixedJson,"$.phoneNumbers[?(#.type =='home')]")[0].number;
output
0123-4567-8910

Related

Setting a value into a json using jsonPath in karate

I have the below Json File(Test.json) read into a variable in karate
TestInput.json:
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "Mobile",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
I intend to change the value of Mobile number within my karate code and use the Json as my request with the following lines
Karate Code:
* def reqJson = read('TestInput.json')
* karate.set('reqJson','$.phoneNumbers[?(#.type=="Mobile")].number',"999999999")
Then print reqJson
The output of the print statement doesn't have the json updated with the number for Mobile.
Alternatively, I've also used the below line to set the variable, but this hasn't worked either:
* set reqJson.phoneNumbers[?(#.type=="Mobile")].number = "99999999"
Is this possible via Karate? If Yes can someone please point me to the place where I'm going wrong or an alternative approach to achieve my scenario.
Thanks.
You can't use JsonPath to mutate. Directly access the path or use a map() operation: https://github.com/karatelabs/karate#json-transforms
This is just one example assuming the JSON is in a variable called body. Take some time to get used to JSON transforms.
* body.phoneNumbers = body.phoneNumbers.map(x => { x.number = '999'; return x })

JPath for partial query match

I'm trying to learn json jpath query. I have successfully been able to return data based on exact searches.
For example at the site: https://jsonpath.com/ I can successfully retrieve the type of phone based on phone number:
JSON
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
Query
$.[?(#.number== '0123-4567-8888')].type
However I can't find any examples that show me how to match a partial search result. I'm trying to write a query where I provide just "0123" and hence get back both "home" and "iPhone" returned as results.How can I do this?
You can use =~ match filter operator which allows providing a regular expression instead of strict value so given you amend your query like:
$.phoneNumbers[?(#.number=~/.*0123.*/)].type
you will get both types as the result:
More information: JMeter's JSON Path Extractor Plugin - Advanced Usage Scenarios

JSON query with JsonPath by sibling node condition

This is a problem I am having for JSON parsing with JsonPath. I do come up with a solution but not sure if it is the best/only.
Suppose I have a simple JSON like this,
{
"name": "Bill",
"age" : 33
}
I need to select the "name" node if the value of "age" node is less than 40. If it is not, just return an empty array.
Could anyone share your solution? I have mine as one answer below.
First I have to use $. to turn the JSON into an array of JSON, ie,
{
"name": "Bill",
"age" : 33
}
to
[
{
"name": "Bill",
"age" : 33
}
]
Then I can apply $[?(#.age < 40)].name

Map Reduce to parse JSON data in hadoop 2.2

Hello I have a JSON in the following format.I need to parse this in the map function to get the gender information of all the records.
[
{
"SeasonTicket" : false,
"name" : "Vinson Foreman",
"gender" : "male",
"age" : 50,
"email" : "vinsonforeman#cyclonica.com",
"annualSalary" : "$98,501.00",
"id" : 0
},
{
"SeasonTicket": true,
"name": "Genevieve Compton",
"gender": "female",
"age": 28,
"email": "genevievecompton#cyclonica.com",
"annualSalary": "$46,881.00",
"id": 1
},
{
"SeasonTicket": false,
"name": "Christian Crawford",
"gender": "male",
"age": 53,
"email": "christiancrawford#cyclonica.com",
"annualSalary": "$53,488.00",
"id": 2
}
]
I have tried using JSONparser but am not able to get through the JSON structure.I have been advised to use JAQL and pig but cannot do so.
Any help would be appreciated.
What I understand is that you have a huge file with an array of JSONs. Of this, you need to read the same to a mapper and emit say <id : gender>. The challenge is that JSON falls across to multiple lines.
In this is the case, I would suggest you to change the default delimiter to "}" instead of "\n".
In this case, you will be able to get parts of the JSON into the map method as value. You can discard the key ie. byte offset and do slight re-fractor on the value like removing off unwanted [ ] or , and adding chars like "}" and then parse the remaining string.
This solution works because there is no nesting within JSON and } is a valid JSON end delimiter as per the given example.
For changing the default delimiter, just set the property textinputformat.record.delimiter to "}"
Please check out this example.
Also check this jira.

jqGrid JSON notation on objects

there!
I´ve one column in my jqGrid that is empty.
But i checked the object on chrome console and thats fine.
colModel definition
colModel:[
{name:'id',index:'id', width:55,editable:false,editoptions:{readonly:true,size:10},hidden:true},
{name:'firstName',index:'firstName', width:100,searchoptions: { sopt: ['eq', 'ne', 'cn']}},
{name:'lastName',index:'lastName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'books[0].nome',index:'books[0].nome', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{"formatter":"myfunction", formatoptions:{baseLinkUrl:'/demo/{firstName}|view-icon'}}
]
JSON response
{
"total": "10",
"page": "1",
"records": "3",
"rows": [
{
"id": 1,
"firstName": "John",
"lastName": "Smith",
"books": [{"nome": "HeadFirst"}]
},
{
"id": 2,
"firstName": "Jane",
"lastName": "Adams",
"books": [{"nome": "DalaiLama"}]
},
{
"id": 35,
"firstName": "Jeff",
"lastName": "Mayer",
"books": [{"nome": "Bobymarley"}]
}
]
}
chrome console inspect object
rowdata.books[0].nome
"HeadFirst"
Any one know where theres are possibles trick?
Tks!
You should use as the value of name property of colModel only the names which can be used as property name in JavaScript and as CSS id names. So the usage of name:'books[0].nome' is not good idea.
To solve your problem you can use jsonmap. For example you can use dotted name conversion:
{name: 'nome', jsonmap: 'books.0.nome', ...
In more complex cases you can use functions as the value of jsonmap. For example
{name: 'nome', jsonmap: function (item) {
return item.books[0].nome;
}, ...
You can find some more code examples about the usage of jsonmap in other old answers: here, here, here, here, here.
name is intended to be a unique name for the row, not a reference to a JSON object. From the jqGrid colModel options documentation:
Set the unique name in the grid for the column. This property is required. As well as other words used as property/event names, the reserved words (which cannot be used for names) include subgrid, cb and rn.
You can also observe how .name is used within grid.base.js - for example:
var nm = {},
...
nm = $t.p.colModel[i].name;
...
res[nm] = $.unformat.call($t,this,{rowId:ind.id, colModel:$t.p.colModel[i]},i);
Anyway, to get back to your question I think you will have better luck by passing down the book name directly - as strings and not objects - and referencing it by name as something like bookName.