JSON.net parsing of dynamic JSON - json

I have JSON that looks like this:
{
"status": {
"code": 0,
"message": "OK"
},
"data": {
"_idtype": "cusip",
"_id": "00768Y883",
"api": {
"_name": "PortfolioBreakdownsRaw",
"PortfolioDate": "2015-10-12",
"GlobalBondSuperSectorLongSalePositionBreakdown": [
{
"Name": "Municipal",
"Value": "0.57842"
},
{
"Name": "Corporate",
"Value": "1.79649"
},
{
"Name": "Securitized",
"Value": "5.29493"
},
{
"Name": "Cash & Equivalents",
"Value": "166.20776"
}
],
"GlobalBondSuperSectorShortSalePositionBreakdown": [
{
"Name": "Government",
"Value": "0.90557"
}
]
}
}
}
I am able to get the api portion of the response easily:
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
From here, I don't what if any arrays will be included in the response. The ultimate goal will be to create a parser that will be able to get the array names (GlobalBondSuperSectorShortSalePositionBreakdown) and as many rows of key-value pairs that it may contain, without first knowing the names such as (GlobalBondSuperSectorShortSalePositionBreakdown) beforehand.
I can't seem to find a good way to loop through the object, determine there are arrays at the api level and then iterate through those to get the values.
Any help would be appreciated.

Here's an example. In this code, the api variable holds a JObject, so we can iterate over its properties. From there, we look at the Type of each property value to see if it is an array or not. If it is, then we can iterate over that array to get the JObjects within it, and extract the Name and Value values that we expect to find there. Does this help?
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
foreach (JProperty prop in api.Children<JProperty>())
{
JToken value = prop.Value;
if (value.Type == JTokenType.Array)
{
Console.WriteLine(prop.Name + ": ");
foreach (JObject jo in value.Children<JObject>())
{
Console.WriteLine(" " + jo["Name"] + ": " + jo["Value"]);
}
}
else
{
Console.WriteLine(prop.Name + ": " + value);
}
}
Output:
_name: PortfolioBreakdownsRaw
PortfolioDate: 2015-10-12
GlobalBondSuperSectorLongSalePositionBreakdown:
Municipal: 0.57842
Corporate: 1.79649
Securitized: 5.29493
Cash & Equivalents: 166.20776
GlobalBondSuperSectorShortSalePositionBreakdown:
Government: 0.90557
Fiddle: https://dotnetfiddle.net/XyoXQy

With Linq you can play pretty nice with Json.net:
Here is an easily readable version of the chunk of code that will create two dictionaries out of the JArray properties under the api element:
var api = jObject["data"]["api"];
var arrays = api.Cast<JProperty>().Where(o => o.Value.Type == JTokenType.Array).Select(token => token.Value).ToArray();
var dictionaries = new List<Dictionary<string, string>>();
foreach (var array in arrays)
{
var dictionary = array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>());
dictionaries.Add(dictionary);
}
alternative:
The same thing, but a shorter, more compact version :
var api = jObject["data"]["api"];
var dictionaries = api
.Cast<JProperty>()
.Where(o => o.Value.Type == JTokenType.Array)
.Select(token => token.Value)
.Select(array => array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>()));

Related

DocumentDB: bulkImport Stored Proc - Getting 400 Error on Array/JSON issue

I'm simply trying to execute the standard example bulkImport sproc for documentDB API and I can't seem to pass it an array of objects. I always get 400 errors despite the documentation giving clear direction to send an array of objects
.. very frustrating.
Additional details: Even if I wrap the array in an object with the array under a property of 'items' and include it in my sproc it still errors out saying the same bad request, needs to be an object or JSON-serialized. When I try to do JSON.stringify(docs) before sending it fails to parse on the other side.
Bad Request: The document body must be an object or a string representing a JSON-serialized object.
bulkInsert.js:
https://github.com/Azure/azure-documentdb-js-server/blob/master/samples/stored-procedures/BulkImport.js
My Code (using documentdb-util for async):
execProc(docs, insertProc);
async function execProc(docs, insertProc){
let database = await dbUtil.database('test');
let collection = await dbUtil.collection(database, 'test');
let procInstance = await dbUtil.storedProcedure(collection, insertProc);
try{
let result = await dbUtil.executeStoredProcedure(procInstance, docs);
console.log(result);
} catch(e){
console.log(e.body)
}
}
Header
Object {Cache-Control: "no-cache", x-ms-version: "2017-11-15",
User-Agent: "win32/10.0.16299 Nodejs/v8.9.0 documentdb-nodejs-s…",
x-ms-date: "Mon, 11 Dec 2017 07:32:29 GMT",
Accept:"application/json"
authorization: myauth
Cache-Control:"no-cache"
Content-Type:"application/json"
User-Agent:"win32/10.0.16299 Nodejs/v8.9.0 documentdb-nodejs-sdk/1.14.1"
x-ms-date:"Mon, 11 Dec 2017 07:32:29 GMT"
x-ms-version:"2017-11-15"
Path
"/dbs/myDB/colls/myColl/sprocs/myBulkInsert"
Params
Array(3) [Object, Object, Object]
length:3
0:Object {id: "0001", type: "donut", name: "Cake", …}
1:Object {id: "0002", type: "donut", name: "Raised", …}
2:Object {id: "0003", type: "donut", name: "Old Fashioned", …}
[{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.35
},
{
"id": "0003",
"type": "donut",
"name": "Old Fashioned",
"ppu": 0.25
}]
The "docs" must be an array of array of params, otherwise, the procedure executor will treat them as multiple params of the procedure, not a single-array-param.
the following code works when call storedProcedure to pass argument with array type.
JS:
var docs = [{'id':1},{'id':2}];
executeStoredProcedure(proc, [docs])
C#
var docs = new[] {new MyDoc{id=1, source="abc"}, new MyDoc{id=2, source="abc"}];
dynamic[] args = new dynamic[] {docs};
ExecuteStoredProcedureAsync<int>(
procLink,
new RequestOptions {PartitionKey = new PartitionKey("abc")},
args);
NOTE: you must ensure the 'docs' have the same partition key, and pass partion key in RequestionOptions
I had the same problem. I was able to get it to work by Stringify the Array and parse it in the stored procedure. I opened an issue on the github where that code originated as well. Below is what worked for me. Good luck.
---- Stringify Array
var testArr = []
for (var i = 0; i < 50; i++) {
testArr.push({
"id": "test" + i
})
}
var testArrStr = JSON.stringify(testArr)
//pass testArrStr to stored procedure and parse in stored procedure
---- Slightly altered original BulkImport
exports.storedProcedure = {
id: "bulkImportArray",
serverScript:function bulkImportArray(docs) {
var context = getContext();
var collection = context.getCollection();
var docsToCreate = JSON.parse(docs)
var count = 0;
var docsLength = docsToCreate.length;
if (docsLength == 0) {
getContext().getResponse().setBody(0);
}
var totals = ""
function insertDoc(){
var msg = " count=" + count+" docsLength=" +docsLength + " typeof docsToCreate[]=" + typeof docsToCreate+ " length =" + docsToCreate.length
if(typeof docsToCreate[count] != 'undefined' ) {
collection.createDocument(collection.getSelfLink(),
docsToCreate[count],
function (err, documentCreated) {
if (err){
// throw new Error('Error' + err.message);
getContext().getResponse().setBody(count + " : " + err);
}else{
if (count < docsLength -1) {
count++;
insertDoc();
getContext().getResponse().setBody(msg);
} else {
getContext().getResponse().setBody(msg);
}
}
});
}else{
getContext().getResponse().setBody(msg);
}
}
insertDoc()
}
}
If you want to test it in the portal Script Explorer I had to create an escaped string i.e.
var testArr = []
for(var i=200; i<250; i++){
testArr.push({"id":"test"+i})
}
var testArrStr = JSON.stringify(testArr)
console.log('"'+testArrStr.replace(/\"/g,'\\"') + '"')

UWP - From Json string to Structure (Classes)

I receive a JSon string from WS. It's so long that I can't use Json2charp to parse it and receive the structurated class.
I want to parse the string with a command. How is it possible?
I don't know the classes so I can't use a command like:
Dim result = JsonConvert.DeserializeObject(Of MyClass.RootObject)(String_From_File)
Is it possible from the string to obtain the class without using json2charp site ?
For example, in vs.net if on the variable 'string_from_file' I choose 'Json Visualizer' and see all classes and data in correct mode.
How can I obtain the same in my code ?
I have installed Newtonsoft.json
If you cannot use the json to class mappers like NewtonSoft.Json. You can use the Windows.Data.Json api. It let you parse and extract the data you want from your JSON string.
JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");
You can find a sample in the Windows Universal Sample GitHub.
A complex object parsing is shown here. I've extracted the most relevant parts here. The JSON string is provided to the User constructor which is extracting what it needs and then delegating the parsing to the nested School constructor.
{
"id": "1146217767",
"phone": null,
"name": "Satya Nadella",
"education": [
{
"school": {
"id": "204165836287254",
"name": "Contoso High School"
},
"type": "High School"
},
{
"school": {
"id": "116138758396662",
"name": "Contoso University"
},
"type": "College"
}
],
"timezone": -8,
"verified": true
}
This JSON fragment is parsed with this code:
public User(string jsonString) : this()
{
JsonObject jsonObject = JsonObject.Parse(jsonString);
Id = jsonObject.GetNamedString(idKey, "");
IJsonValue phoneJsonValue = jsonObject.GetNamedValue(phoneKey);
if (phoneJsonValue.ValueType == JsonValueType.Null)
{
Phone = null;
}
else
{
Phone = phoneJsonValue.GetString();
}
Name = jsonObject.GetNamedString(nameKey, "");
Timezone = jsonObject.GetNamedNumber(timezoneKey, 0);
Verified = jsonObject.GetNamedBoolean(verifiedKey, false);
foreach (IJsonValue jsonValue in jsonObject.GetNamedArray(educationKey, new JsonArray()))
{
if (jsonValue.ValueType == JsonValueType.Object)
{
Education.Add(new School(jsonValue.GetObject()));
}
}
}
public School(JsonObject jsonObject)
{
JsonObject schoolObject = jsonObject.GetNamedObject(schoolKey, null);
if (schoolObject != null)
{
Id = schoolObject.GetNamedString(idKey, "");
Name = schoolObject.GetNamedString(nameKey, "");
}
Type = jsonObject.GetNamedString(typeKey);
}
If you cannot use the automatic mapping from NewtonSoft.Json, you have no other way than doing it yourself.
Is not so simple.
The Json i received is very complicated and have many class
So i can't use
double width = jsonValue.GetObject().GetNamedNumber("Width");
Inside class i have more ...

How to use JObject.FromObject to get a json with no propertyname

I use NewtonSoft JSON.Net. I have a collection of namevalue pair and i need to get a json that looks like
{"cot":"1","mac":"2","cot":"8"}
Note that i can have duplicate names here.
I have two options here
a) i can use Dictionary as my underlying collection and when i do, i get the desired result but i cant add duplicate key.
b) i have have a list of KeyValuePair but in this case, the result json is not in the structure i wanted.
Any idea how to get the desired result? thanks!
var listData = new List<KeyValuePair<string, string>>();
listData.Add(new KeyValuePair<string, string>("cot", "1"));
listData.Add(new KeyValuePair<string, string>("mat", "1"));
listData.Add(new KeyValuePair<string, string>("cot", "2"));
var dicData = new Dictionary<string, string>();
dicData.Add("cot", "1");
dicData.Add("mat", "1");
Console.WriteLine("Output from LIST");
Console.WriteLine(JArray.FromObject(listData));
Console.WriteLine();
Console.WriteLine("Output from Dictionary");
Console.WriteLine(JObject.FromObject(dicData));
Output from LIST
[
{
"Key": "cot",
"Value": "1"
},
{
"Key": "mat",
"Value": "1"
},
{
"Key": "cot",
"Value": "2"
}
]
Output from Dictionary
{
"cot": "1",
"mat": "1"
}
The JSON
'{"cot":"1","mac":"2","cot":"8"}'
will parse to a javscript object :
{"cot":"8","mac":"2"}.
Try
dicData.Add("cot", "8")
and see if it gets what you want.
You can also try concatenating strings until you get the desired JSON.
Like
var jsonOutput = "{"
//for each key value...
jsonOutput += "key : "+ value.toString + ","
//...etc
//then remove the last trailing comma, and add a "}"

IBM Worklight Adapter parsing JSON

{
"isSuccessful": true,
"resultSet": [
{
"name": "pradeep",
"password": 123,
"timestamp": "2014-04-08T12:58:45.000Z"
},
{
"name": "dileep",
"password": 1234,
"timestamp": "2014-04-08T13:00:52.000Z"
}
]
}
This invocation result i have got by using Sql adapter so how to parse this invocation result and how can i display name,password,timestamp from this JSON object.Do i need to use HTTP Adapter.
If you want to get the length of results you should use result.invocationResult.resultSet.length which will give you the total number of results, where items is the response coming from the adapter and invocationResult contains the results and other paramaters, from which you will have to access the results for accessing only the particular output.To get value call
result.invocationResult.resultSet.name[position]
Like that call all the fields password,timestamp with position
in for loop
function handleSuccess(result) {
var invocationResult = result.invocationResult;
var isSuccessful = invocationResult.isSuccessful;
if (true == isSuccessful) {
var result = invocationResult.resultSet;
for ( var i = 0; i < result.length; i++) {
alert(result.name[i]);
alert(result.password[i]);
alert(result.timestamp[i]);
}
} else {
alert("error");
}

Actionscript3 parsing json with an object

I have a flash app where in a function I have to parse a json passed like an object by some external API that I can't change.
my json look like this:
{
"prodotti": [
{
"titolo": "test",
"marca": "",
"modello": "",
"cilindrata": "",
"potenza": "",
"alimentazione": "",
"images": {
"img": [
{
"thumb": "admin/uploads/img_usato/small/qekabw95L5WH1ALf6.jpg",
"big": "admin/uploads/img_usato/big/qekabw95L5WH1ALf6.jpg"
},
{
"thumb": "admin/uploads/img_usato/small/default.jpg",
"big": "admin/uploads/img_usato/big/default.jpg"
}
]
}
},
{
"titolo": "Motore Volvo TAMD 74 C",
"marca": "VOLVO PENTA",
"modello": "TAMD 74 C",
"cilindrata": "7.283 cm3",
"potenza": "331 kW a 2600 rpm",
"alimentazione": "Gasolio",
"images": {
"img": [
{
"thumb": "admin/uploads/img_usato/small/PmQwN4t4yp7P1YCWa.jpg",
"big": "admin/uploads/img_usato/big/PmQwN4t4yp7P1YCWa.jpg"
},
{
"thumb": "admin/uploads/img_usato/small/BWkjTGcy3pDM2LKRs.jpg",
"big": "admin/uploads/img_usato/big/BWkjTGcy3pDM2LKRs.jpg"
}
]
}
}
]
}
I want to parse the images inside the object.
The API send me an object not astring or json and I have this function now:
function changeData (prodotto:Object) {
img_container.graphics.clear ();
//here I want to enter and take thumb and big of images!!!
for (var index in prodotto.images.img) {
//trace('index: ' + index);
//trace("thumb: " + index.thumb + ' big: ' + index.big);
}
descrizione.htmlText = prodotto.testo_html;
titolo.text = prodotto.titolo;
alimentazione.text = prodotto.alimentazione;
potenza.text = prodotto.potenza;
cilindrata.text = prodotto.cilindrata;
modello.text = prodotto.modello;
marca.text = prodotto.marca;
}
The function works fine but not for the for loop where I try to take the bug and thumb of my json how can I retrieve this information in this object?
Thanks
I think there is something wrong with how you are setting up the call back but since you didn't show code for the api we can't fix that, plus you stated you have no control over it.
No matter what the issue is it just does not seem correct.
I put together a function that will get all the thumbs and bigs.
You did not state otherwise.
function changeData (prodotto:Object) {
for each(var item in prodotto.prodotti){
trace('')
//trace(prodotto.testo_html);
trace(item.titolo);
trace(item.alimentazione);
trace(item.potenza);
trace(item.cilindrata);
trace(item.modello);
trace(item.marca);
for each( var imgs in item.images.img) {
trace('thumb',imgs.thumb)
trace('big',imgs.big)
}
}
}
I think you need to use a JSON parser. Use the one from this link: https://github.com/mikechambers/as3corelib
1: Add the com folder to your project directory or add it to your default class path.
2: Adapt this code to your liking. I am not sure how you're getting a literal object from the API. It really should just be a string unless you're using some sort of AMF. Regardless...
import com.adobe.serialization.json.*;
var data:String = '{"prodotti":[{"titolo":"test","marca":"","modello":"","cilindrata":"","potenza":"","alimentazione":"","images":{"img":[{"thumb":"admin/uploads/img_usato/small/qekabw95L5WH1ALf6.jpg","big":"admin/uploads/img_usato/big/qekabw95L5WH1ALf6.jpg"},{"thumb":"admin/uploads/img_usato/small/default.jpg","big":"admin/uploads/img_usato/big/default.jpg"}]}},{"titolo":"Motore Volvo TAMD 74 C","marca":"VOLVO PENTA","modello":"TAMD 74 C","cilindrata":"7.283 cm3","potenza":"331 kW a 2600 rpm","alimentazione":"Gasolio","images":{"img":[{"thumb":"admin/uploads/img_usato/small/PmQwN4t4yp7P1YCWa.jpg","big":"admin/uploads/img_usato/big/PmQwN4t4yp7P1YCWa.jpg"},{"thumb":"admin/uploads/img_usato/small/BWkjTGcy3pDM2LKRs.jpg","big":"admin/uploads/img_usato/big/BWkjTGcy3pDM2LKRs.jpg"}]}}]}';
function changeData(data)
{
img_container.graphics.clear();
var obj = JSON.decode(data);
for (var i:int = 0; i < obj.prodotti.length; i++)
{
for (var k in obj.prodotti[i].images.img)
{
trace("Thumb:",obj.prodotti[i].images.img[k].thumb);
trace("Big:",obj.prodotti[i].images.img[k].big);
}
descrizione.htmlText = obj.prodotti[i].testo_html;
titolo.text = obj.prodotti[i].titolo;
alimentazione.text = obj.prodotti[i].alimentazione;
potenza.text = obj.prodotti[i].potenza;
cilindrata.text = obj.prodotti[i].cilindrata;
modello.text = obj.prodotti[i].modello;
marca.text = obj.prodotti[i].marca;
}
}
changeData(data);