I'm working on a service in which I pass a JSON request, I need to convert it to XML and them compare it to some XML schemas and then do something with it.
My problem is with the attributes. For example, my JSON request is:
{
"BookingSearch_IN": {
"MsgHeader": {
"MessageID": "ABC010101",
"ContextRecord": {
"ContextInfo": {
"ItineraryDetails": {
"ItinerarySeqNmbr": "1",
"StartDate": "2017-04-01",
"EndDate": "2017-04-14",
"LocationStart": {
"LocationContext": "AIRPORT",
"LocationCode": "MIA"
},
"LocationEnd": {
"LocationContext": "AIRPORT",
"LocationCode": "MIA"
}
},
"ExtraInfoList": {
"ExtraInfo": {
"Category": "CRUISE",
"Item": {
"Code": "SHIP_CODE",
"Value": "MAGIC"
}
}
},
"_ResType": "Vacation"
}
}
},
"_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"_xmlns:cs": "http://MyCompany.com",
"_version": "6.66",
"__prefix": "cs"
}
}
I'm using: XmlDocument doc = JsonConvert.DeserializeXmlNode(jsonObject); to convert it to XML. The xml result is:
<BookingSearch_IN>
<MsgHeader>
<MessageID>ABC010101</MessageID>
<ContextRecord>
<ContextInfo>
<ItineraryDetails>
<ItinerarySeqNmbr>1</ItinerarySeqNmbr>
<StartDate>2017-04-01</StartDate>
<EndDate>2017-04-14</EndDate>
<LocationStart>
<LocationContext>AIRPORT</LocationContext>
<LocationCode>MIA</LocationCode>
</LocationStart>
<LocationEnd>
<LocationContext>AIRPORT</LocationContext>
<LocationCode>MIA</LocationCode>
</LocationEnd>
</ItineraryDetails>
<ExtraInfoList>
<ExtraInfo>
<Category>CRUISE</Category>
<Item>
<Code>SHIP_CODE</Code>
<Value>MAGIC</Value>
</Item>
</ExtraInfo>
</ExtraInfoList>
<_ResType>Vacation</_ResType>
</ContextInfo>
</ContextRecord>
</MsgHeader>
<xsi>http://www.w3.org/2001/XMLSchema-instance</xsi><cs>http://MyCompany.com</cs><_version>6.66</_version><__prefix>cs</__prefix>
</BookingSearch_IN>
The result XML has the attributes of the root element at the end of the document, as another elements (between </MsgHeader> and </BookingSearch_IN>). My problem is that the service that validates this XML against other customers' XML checks these attributes in the root element. Here is how the code expects the XML to be:
<?xml version="1.0" encoding="UTF-8"?>
<cs:BookingSearch_IN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cs="http://MyCompany.com" version="6.66">
<MsgHeader>
<MessageID>ABC010101</MessageID>
<ContextRecord>
<ContextInfo ResType="Vacation">
<ItineraryDetails>
<ItinerarySeqNmbr>1</ItinerarySeqNmbr>
<StartDate>2017-04-01</StartDate>
<EndDate>2017-04-14</EndDate>
<LocationStart>
<LocationContext>AIRPORT</LocationContext>
<LocationCode>MIA</LocationCode>
</LocationStart>
<LocationEnd>
<LocationContext>AIRPORT</LocationContext>
<LocationCode>MIA</LocationCode>
</LocationEnd>
</ItineraryDetails>
<ExtraInfoList>
<ExtraInfo>
<Category>CRUISE</Category>
<Item>
<Code>SHIP_CODE</Code>
<Value>MAGIC</Value>
</Item>
</ExtraInfo>
</ExtraInfoList>
</ContextInfo>
</ContextRecord>
</MsgHeader>
</cs:BookingSearch_IN>
The code fails because it expect the root element to be <cs:BookingSearch_IN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cs="http://MyCompany.com" version="5.22">
.... any advise on how to handle this situation? or how to put those attributes back to where they belong in the root element?
NewtonSoft expects attributes to be prefixed with #, not _ or __, and expects prefixes to just be baked into the names. For example, if you can get your JSON to look like this:
{
"cs:BookingSearch_IN": {
"#xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"#xmlns:cs": "http://MyCompany.com",
"#version": "6.66",
"MsgHeader": {
"MessageID": "ABC010101",
"ContextRecord": {
"ContextInfo": {
"#ResType": "Vacation",
"ItineraryDetails": {
"ItinerarySeqNmbr": "1",
"StartDate": "2017-04-01",
"EndDate": "2017-04-14",
"LocationStart": {
"LocationContext": "AIRPORT",
"LocationCode": "MIA"
},
"LocationEnd": {
"LocationContext": "AIRPORT",
"LocationCode": "MIA"
}
},
"ExtraInfoList": {
"ExtraInfo": {
"Category": "CRUISE",
"Item": {
"Code": "SHIP_CODE",
"Value": "MAGIC"
}
}
}
}
}
}
}
}
It will work correctly (note that you have to move those XMLNS's up to the top - if they stay where they are at the bottom, it drops the prefix for some reason).
If that's not possible, you'll either have to use a different serializer or write some custom logic to pre/post process your JSON or XML.
Related
I'm attempting to run some patch operations:
ItemResponse<dynamic> response = await _container.PatchItemAsync<dynamic>(
id: loanParent.LoanNumber,
partitionKey: new PartitionKey(loanParent.LoanNumber),
patchOperations: new[] {
PatchOperation.Replace("/loandetails/loanname", loanParent.Loan.LoanDetails.LoanName),
PatchOperation.Replace("/loandetails/loandescription", loanParent.Loan.LoanDetails.LoanDescription)
}
);
However, I'm getting this exception because those nodes do not exist yet. Here's the full document:
{
"loannumber": "abc123",
"id": "abc123",
"participants": [
{
"firstname": "alex",
"lastname": "gordon"
},
{
"firstname": "liza",
"lastname": "gordon"
}
],
"_rid": "1sAyAggggggA==",
"_self": "dbs/1sAyAA=gggggAAAAAAAA==/",
"_etag": "\"d900c069-0000-4440-0000-63642d840000\"",
"_attachments": "attachments/",
"_ts": 1ddd636
}
Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: BadRequest (400); Substatus: 0; ActivityId: a6ab67d6-f73e-4b3c-b03e-1d9b6cc54dba; Reason: (Message: {"Errors":["For Operation(1): Given Operation can only create a child object of an existing node(array or object) and cannot create path recursively, no path found beyond: 'loandetails'. Learn more: https://aka.ms/cosmosdbpatchdocs"]}
How do we create the node structure if it does not exist?
Patch works on an existing document, you need to make sure the object exists before you perform any operations such as add,remove,replace,set and increment.
In this case first you can use Add operator to create the loandetails and then the subsequent operations can be performed
I have JSON file in Azure Storage which I am reading using C#. In that JSON file there is anode called SQLViewDifinition and that node I have SQL which I need to fetch.
I have read the file into a string and converted that string in JObject. I have the JSON now but is finding it difficult to read that particular node. Tried with JToken and Jproperty. But could not crack it.
JSON file looks like this:
{
"jsonSchemaSemanticVersion": "1.4.0",
"imports": [
{
"corpusPath": "cdm:/foundations.cdm.json"
},
{
"corpusPath": "localCdm:/foundations.cdm.json"
}
],
"definitions": [
{
"entityName": "METCredManCollectionGroupEntity",
"exhibitsTraits": [
{
"traitReference": "is.CDM.entityVersion",
"arguments": [
{
"name": "versionNumber",
"value": "1.0.0"
}
]
},
{
"traitReference": "has.sqlViewDefinition",
"arguments": [
{
"name": "sqlViewDefinition",
"value": "CREATE VIEW [DBO].[METCREDMANCOLLECTIONGROUPENTITY] AS SELECT T1.COLLECTIONGROUPID AS COLLECTIONGROUPID, T1.DESCRIPTION AS DESCRIPTION, T1.RECID AS CREDMANCOLLECTIONGROUPTABLERECID, T1.DATAAREAID AS CREDMANCOLLECTIONGROUPTABLEDATAAREAID, T1.RECVERSION AS RECVERSION, T1.PARTITION AS PARTITION, T1.RECID AS RECID FROM CREDMANCOLLECTIONGROUPTABLE T1"
}
]
},
{
"traitReference": "has.backingElements",
"arguments": [
{
"name": "backingElements",
"value": "CredManCollectionGroupTable"
}
]
}
],
"hasAttributes": [
{
"name": "CollectionGroupId",
"dataType": "CredManCollectionGroupId",
"isNullable": true,
"displayName": "Collection group",
"maximumLength": 10
},
{
"name": "Description",
"dataType": "Description",
"isNullable": true,
"displayName": "Description",
"maximumLength": 60
},
{
"name": "CredmanCollectionGroupTableRecId",
"dataType": "other",
"isNullable": true,
"displayName": "Record-ID"
},
{
"name": "CredmanCollectionGroupTableDataAreaId",
"dataType": "other",
"isNullable": true,
"displayName": "Company"
}
],
"displayName": "MET Collection groups (Shared)"
},
{
"explanation": "Collection group",
"dataTypeName": "CredManCollectionGroupId",
"extendsDataType": "SysGroup"
},
{
"explanation": "Group",
"dataTypeName": "SysGroup",
"extendsDataType": "string"
},
{
"explanation": "Description",
"dataTypeName": "Description",
"extendsDataType": "string"
}
]
}
I need to find sqlViewDefinition from this file.
So far I can read the JSON in a JSON object. But could not find a way to get the view definition.
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Nancy.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class FindFiles
{
// Main Method with int return type
static int Main(String[] args)
{
Console.WriteLine("Buid SQL");
// for successful execution of code
return X("FILE_NAME");
}
public static int X(string fileName)
{
//connection string
string storageAccount_connectionString = "CONNECTION_STRING";
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccount_connectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("CONTAINER");
//The specified container does not exist
try
{
//root directory
CloudBlobDirectory dira = container.GetDirectoryReference(string.Empty);
//true for all sub directories else false
var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result;
foreach (var blob in rootDirFolders.Results)
{
if (blob.Uri.OriginalString.Contains(fileName, StringComparison.OrdinalIgnoreCase) && blob.Uri.OriginalString.Contains(".cdm.json", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Blob: " + blob.Uri.OriginalString);
if (blob.GetType() == typeof(CloudBlockBlob))
{
CloudBlockBlob b = (CloudBlockBlob)blob;
string jsonText = b.DownloadTextAsync().Result;
Dictionary<string, object> json_Dictionary = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(jsonText.ToString());
JObject json = JObject.Parse(jsonText);
}
}
}
}
catch (Exception e)
{
// Block of code to handle errors
Console.WriteLine("Error", e);
}
return 1;
}
}
As you are using .NET 6 and because the structure is always the same, the easiest way to deserialize is to mimic the structure of the JSON in C# classes. You can then easily deserialize the JSON into objects and access the properties of the objects instead of "brachiating" through dynamic data.
In order to get the classes, you can use Visual Studio's Paste Special function (Edit -> Paste special -> Paste JSON as classes). This generates the classes for you (you can adjust the classes if you don't need parts of them or change the casing of the property names; also you can use attributes to customize the serialization).
Afterwards, it is easy to parse the JSON into an object, e.g. (I've put your sample JSON into the jsonContent variable):
var obj = System.Text.Json.JsonSerializer.Deserialize<Rootobject>(jsonContent);
Because it still is a complex structure, getting to the SQL needs a bit of code:
Console.WriteLine(obj
.definitions[0]
.exhibitsTraits
.Where(x => x.traitReference == "has.sqlViewDefinition")
.First().arguments.Where(x => x.name == "sqlViewDefinition")
.First().value);
Finally, the above code writes the following output:
CREATE VIEW [DBO].[METCREDMANCOLLECTIONGROUPENTITY] AS SELECT T1.COLLECTIONGROUPID AS COLLECTIONGROUPID, T1.DESCRIPTION AS DESCRIPTION, T1.RECID AS CREDMANCOLLECTIONGROUPTABLERECID, T1.DATAAREAID AS CREDMANCOLLECTIONGROUPTABLEDATAAREAID, T1.RECVERSION AS RECVERSION, T1.PARTITION AS PARTITION, T1.RECID AS RECID FROM CREDMANCOLLECTIONGROUPTABLE T1
You can use this documentation to get familiar with JSON handling in .NET 6.
I'm trying to call update functions from MyCouch. The documentation of Mycouch reports only an outdated example with Post method on _design documents.
But how to consume an Update function
{
"_id": "_design/artists",
"language": "javascript",
"views": {
"albums": {
"map": "function(doc) { if(doc.$doctype !== 'artist') return; emit(doc.name, doc.albums);}"
}
}
};
client.Documents.Post(designDocumentAsJson);
How to execute the update function on _design couchDB pushing a new document ?
The couchDB documentation tells about this call
PUT /{db}/_design/{ddoc}/_update/{func}/{docid}
PUT /{db}/_design/{ddoc}/_update/{func}/{docid}
Executes update function on server side for the specified document.
Parameters:
db – Database name
ddoc – Design document name
func – Update function name
docid – Document ID
You can insert Design document like below to db: https://docs.couchdb.org/en/stable/api/ddoc/render.html#db-design-design-doc-update-update-name
{
"_id": "_design/albums",
"language": "javascript",
"updates": {
"addAlbum": "function(doc, req) {\n if (!doc){\n return [null, {'code': 400,\n 'json': {'error': 'missed',\n 'reason': 'no document to update'}}]\n } else {\n var body = JSON.parse(req.body);\n doc.albums.push(body.album);\n return [doc, {'json': {'status': 'ok'}}];\n }\n}\n"
}
}
function (Without stringifying):
function(doc, req) {
if (!doc){
return [null, {'code': 400,
'json': {'error': 'missed',
'reason': 'no document to update'}}]
} else {
var body = JSON.parse(req.body);
doc.albums.push(body.album);
return [doc, {'json': {'status': 'ok'}}];
}
}
Example doc:
{
"_id": "albumsId1",
"albums": [
1
]
}
After Api
Request:
POST http://localhost:5984/test/_design/albums/_update/addAlbum/albumsId1
Content-Type:application/json
Accept:application/json
{"album":2}
Response:
{
"status": "ok"
}
doc after updating
{
"_id": "albumsId1",
"_rev": "19-7edb16db3bae388685f554138d562bd0",
"albums": [
1,
2
]
}
On rare occasion when receiving the message "Additional text found in JSON string after finishing deserializing object." the first thing i do is fix some JSON structure typo of mine using JSONLint.
However this time the lint says the json is valid and i can't see where the problem lies. (As i don't control the data's source i need to ldeserialize to a generic object that i then traverse. - Is this possibly the error on my part?)
I'm deserializing with Unity specific Newtonsoft.Json (JsonNet-Lite)
object resultData = JsonConvert.DeserializeObject<object>(jsonString);
What am i missing?
JSON String
"{\"statements\":[{\"id\":\"14b6382c-ddb9-44c5-a22c-a133cec50711\",\"actor\":{\"objectType\":\"Agent\",\"mbox_sha1sum\":\"f7f99253cf6ede467c3a5425d05bfcd96e524595\",\"name\":\"My Name\"},\"verb\":{\"id\":\"https://w3id.org/xapi/dod-isd/verbs/completed\",\"display\":{\"en-US\":\"completed\"}},\"result\":{\"success\":true,\"completion\":true,\"duration\":\"PT0.05S\"},\"context\":{\"contextActivities\":{\"grouping\":[{\"id\":\"http://example.com/activities/MyActivity_Grandparent\",\"objectType\":\"Activity\"}],\"parent\":[{\"id\":\"http://example.com/activities/MyActivity_Parent\",\"objectType\":\"Activity\"}]}},\"timestamp\":\"2018-02-23T19:18:34.145Z\",\"stored\":\"2018-02-23T19:18:34.145Z\",\"authority\":{\"objectType\":\"Agent\",\"account\":{\"homePage\":\"http://cloud.scorm.com\",\"name\":\"abcdef-ghijk\"},\"name\":\"Test Provider\"},\"version\":\"1.0.0\",\"object\":{\"id\":\"http://example.com/activities/MyActivity\",\"definition\":{\"extensions\":{\"https://w3id.org/xapi/dod-isd/extensions/interactivity-level\":\"3\",\"https://w3id.org/xapi/dod-isd/extensions/ksa\":\"Attitude\",\"https://w3id.org/xapi/dod-isd/extensions/category\":\"Responding\",\"http://example.com/TerminalObjective\":\"My Activity Objective\"},\"name\":{\"en-US\":\"My Activity Name\"},\"description\":{\"en-US\":\"My Activity Description\"},\"type\":\"http://adlnet.gov/expapi/activities/simulation\"},\"objectType\":\"Activity\"}}],\"more\":\"/tc/Z5R2XATQZW/sandbox/statements?continueToken=e50555fe-0c3d-4663-91c4-7f0ff7df4ccf\"}"
JSON Formatted for readability
{
"statements": [{
"id": "14b6382c-ddb9-44c5-a22c-a133cec50711",
"actor": {
"objectType": "Agent",
"mbox_sha1sum": "f7f99253cf6ede467c3a5425d05bfcd96e524595",
"name": "My Name"
},
"verb": {
"id": "https://w3id.org/xapi/dod-isd/verbs/completed",
"display": {
"en-US": "completed"
}
},
"result": {
"success": true,
"completion": true,
"duration": "PT0.05S"
},
"context": {
"contextActivities": {
"grouping": [{
"id": "http://example.com/activities/MyActivity_Grandparent",
"objectType": "Activity"
}],
"parent": [{
"id": "http://example.com/activities/MyActivity_Parent",
"objectType": "Activity"
}]
}
},
"timestamp": "2018-02-23T19:18:34.145Z",
"stored": "2018-02-23T19:18:34.145Z",
"authority": {
"objectType": "Agent",
"account": {
"homePage": "http://cloud.scorm.com",
"name": "abcdef-ghijk"
},
"name": "Test Provider"
},
"version": "1.0.0",
"object": {
"id": "http://example.com/activities/MyActivity",
"definition": {
"extensions": {
"https://w3id.org/xapi/dod-isd/extensions/interactivity-level": "3",
"https://w3id.org/xapi/dod-isd/extensions/ksa": "Attitude",
"https://w3id.org/xapi/dod-isd/extensions/category": "Responding",
"http://example.com/TerminalObjective": "My Activity Objective"
},
"name": {
"en-US": "My Activity Name"
},
"description": {
"en-US": "My Activity Description"
},
"type": "http://adlnet.gov/expapi/activities/simulation"
},
"objectType": "Activity"
}
}],
"more": "/tc/Z5R2XATQZW/sandbox/statements?continueToken=e50555fe-0c3d-4663-91c4-7f0ff7df4ccf"
}
The deserialization method, you chose, is rather for a case, when you are deserializing a well-known Json to an object, which matches the structure.
In this case the Json structure does not match the System.Object type structure, you are trying to deserialize to. The library complaints, that there's much more in the Json, than in the System.Object structure.
For parsing any Json object, you could try an example from the Newtonsoft.Json documentation:
string json = #"{
CPU: 'Intel',
Drives: [
'DVD read/writer',
'500 gigabyte hard drive'
]
}";
JObject o = JObject.Parse(json);
You will still need to traverse the deserialized object. Depending on what you want to achieve, it may actually be much better to look for a .Net class that matches the Json structure (or write one).
JSON is really new to me. How can i use JSON.NET to add a key value pair into a already created json file?
It looks like this:
{
"data": {
"subData1": {
"key1":"value1",
"key2":"value2",
"key3":"value3"
},
"subdata2": {
"key4":"value4",
"key5":"value5",
"key6":"value6"
}
}
"key7":"value7",
"key8":"value8"
}
Say for an example that i want to change it to the following:
{
"data": {
"subData1": {
"key1":"value1",
"key2":"value2",
"key3":"value3"
},
"subdata2": {
"key4":"value4",
"key5":"value5",
"key6":"value6"
},
"newSubData": {
"myKey1":"myVal1",
"myKey2":"myVal2",
"myKey3":"myVal3"
}
}
"key7":"anotherValChangeByMe",
"key8":"value8"
}
Do i need to read the whole JSON file into a dynamic, and then change / add the things i need somehow ?
You can parse the JSON into a JObject, manipulate it via the LINQ-to-JSON API, then get the updated JSON string from the JObject.
For example:
string json = #"
{
""data"": {
""subData1"": {
""key1"": ""value1"",
""key2"": ""value2"",
""key3"": ""value3""
},
""subdata2"": {
""key4"": ""value4"",
""key5"": ""value5"",
""key6"": ""value6""
}
},
""key7"": ""value7"",
""key8"": ""value8""
}";
JObject root = JObject.Parse(json);
JObject data = (JObject)root["data"];
JObject newSubData = new JObject();
newSubData.Add("myKey1", "myValue1");
newSubData.Add("myKey2", "myValue2");
newSubData.Add("myKey3", "myValue3");
data.Add("newSubData", newSubData);
root["key7"] = "anotherValChangeByMe";
Console.WriteLine(root.ToString());
Output:
{
"data": {
"subData1": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"subdata2": {
"key4": "value4",
"key5": "value5",
"key6": "value6"
},
"newSubData": {
"myKey1": "myValue1",
"myKey2": "myValue2",
"myKey3": "myValue3"
}
},
"key7": "anotherValChangeByMe",
"key8": "value8"
}
JSON is ultimately just a string. If you are working on the server side, then unless you want to try to parse out the JSON yourself, the easiest way is to use JSON.NET to deserialize it back into it's native object model. Of course, you can also do this on the client side with JSON.parse(), and add the value there, too.