Background: I am currently using VBA-JSON to parse json strings to dictionary objects in VBA (Access). This is quite slow, a sample process takes 18 seconds.
In VB.NET, the JavaScriptSerializer Deserialize method takes .5 seconds for the same data.
I want the performance of the VB.NET method available to my VBA code via COM Interop. But COM cannot pass generic objects and although I have read that the solution involves marshaling, I am having trouble understanding that option.
I can successfully pass a scripting.dictionary type from my VB.NET COM class when I manually generate it and can use it in VBA.
Public Function GetData2() As Scripting.Dictionary
Dim dict As New Scripting.Dictionary
dict.Add("a", "Athens")
dict.Add("b", "Belgrade")
Return dict
End Function
But the JavaScriptSerializer Deserialize method returns a type IDictionary, not a scripting.dictionary.
So I must either find a way to deserialize json to a scripting.dictionary or convert the IDictionary to a scripting.dictionary.
How can I do this?
Given my overall goal, are there any suggestions about alternate methods?
Edit.
The project uses a proprietary REST API for an accounting system. I want to create generic tools to simplify and speed up a variety of different tasks, from environments including Access, Excel, vbscript etc. Everything the API designers intended but from tools not normally friendly to REST API programming.
The uses could range from reading and writing data to and from the system, or loading data into another database, create custom reports in excel, import orders etc.
Here is some JSON for a sales order.
{
"id": 7,
"orderNo": "0000102692",
"division": "000",
"location": "",
"profitCenter": "",
"invoiceNo": "",
"customer": {
"id": 1996,
"code": "ER118",
"customerNo": "ER118",
"name": "E R Partridge Inc"
},
"currency": null,
"status": "O",
"type": "O",
"hold": false,
"orderDate": "2015-02-13",
"invoiceDate": null,
"requiredDate": "2015-02-13",
"address": {
"id": 2045,
"type": "B",
"linkTable": "SORD",
"linkNo": "0000102692",
"shipId": "",
"name": "E R Partridge Inc",
"line1": "1531 St Jean Baptiste St",
"line2": "",
"line3": "",
"line4": "",
"city": "St Ulric",
"postalCode": "G0J 3H0",
"provState": "QC",
"country": "CAN",
"phone": {
"number": "4187370284",
"format": 1
},
"fax": {
"number": "",
"format": 1
},
"email": "[email protected]",
"website": "",
"shipCode": "",
"shipDescription": "",
"salesperson": {
"code": "",
"name": ""
},
"territory": {
"code": "",
"description": ""
},
"sellLevel": 1,
"glAccount": "41100",
"defaultWarehouse": "VA",
"created": "2014-08-26T11:44:57.930000",
"modified": "2015-02-16T09:30:08",
"contacts": [
{
"name": "Van Coon",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
},
{
"name": "",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
},
{
"name": "",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
}
],
"salesTaxes": [
{
"code": 1,
"exempt": ""
},
{
"code": 2,
"exempt": ""
},
{
"code": 0,
"exempt": ""
},
{
"code": 0,
"exempt": ""
}
]
},
"shippingAddress": {
"id": 2044,
"type": "S",
"linkTable": "SORD",
"linkNo": "SORD0000102692 S",
"shipId": "",
"name": "E R Partridge Inc",
"line1": "1531 St Jean Baptiste St",
"line2": "",
"line3": "",
"line4": "",
"city": "St Ulric",
"postalCode": "G0J 3H0",
"provState": "QC",
"country": "CAN",
"phone": {
"number": "4187370284",
"format": 1
},
"fax": {
"number": "",
"format": 1
},
"email": "",
"website": "",
"shipCode": "",
"shipDescription": "",
"salesperson": {
"code": "",
"name": ""
},
"territory": {
"code": "",
"description": ""
},
"sellLevel": 1,
"glAccount": "41100",
"defaultWarehouse": "VA",
"created": "2014-08-26T11:44:57.930000",
"modified": "2014-08-26T11:44:57.930000",
"contacts": [
{
"name": "Van Coon",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
},
{
"name": "",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
},
{
"name": "",
"email": "",
"phone": {
"number": "",
"format": 1
},
"fax": {
"number": "",
"format": 1
}
}
],
"salesTaxes": [
{
"code": 1,
"exempt": ""
},
{
"code": 2,
"exempt": ""
},
{
"code": 0,
"exempt": ""
},
{
"code": 0,
"exempt": ""
}
]
},
"contact": {
"name": "",
"email": "",
"phone": {
"number": "",
"format": 0
},
"fax": {
"number": "",
"format": 0
}
},
"customerPO": "",
"batchNo": 0,
"fob": "Your dock",
"referenceNo": "",
"shippingCarrier": "",
"shipDate": null,
"trackingNo": "",
"termsCode": "",
"termsText": "",
"freight": "41.95",
"taxes": [
{
"code": 1,
"name": "G.S.T.",
"shortName": "G.S.T.",
"rate": "5",
"exemptNo": "",
"total": "44.05"
},
{
"code": 2,
"name": "P.S.T.",
"shortName": "BC P.S.T.",
"rate": "7",
"exemptNo": "",
"total": "61.67"
},
{
"code": 0,
"name": "",
"shortName": "",
"rate": "0",
"exemptNo": "",
"total": 0
},
{
"code": 0,
"name": "",
"shortName": "",
"rate": "0",
"exemptNo": "",
"total": 0
}
],
"subtotal": "839",
"subtotalOrdered": "839",
"discount": "0",
"totalDiscount": "0",
"total": "986.67",
"totalOrdered": "986.67",
"grossProfit": "346.26",
"items": [
{
"id": 8,
"orderNo": "0000102692",
"sequence": 1,
"inventory": {
"id": 40,
"whse": "VA",
"partNo": "INSDB30",
"description": "InSpire Dumbbell 30"
},
"serials": null,
"whse": "VA",
"partNo": "INSDB30",
"description": "InSpire Dumbbell 30",
"comment": "",
"orderQty": "4",
"committedQty": "4",
"backorderQty": "0",
"retailPrice": "70",
"unitPrice": "70",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "INSPIRE",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "280",
"extendedPriceCommitted": "280",
"suppress": false
},
{
"id": 9,
"orderNo": "0000102692",
"sequence": 2,
"inventory": {
"id": 27,
"whse": "VA",
"partNo": "NATACCBAL",
"description": "National Accupressure Balls"
},
"serials": null,
"whse": "VA",
"partNo": "NATACCBAL",
"description": "National Accupressure Balls",
"comment": "",
"orderQty": "5",
"committedQty": "5",
"backorderQty": "0",
"retailPrice": "22",
"unitPrice": "22",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "NATPRO",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "110",
"extendedPriceCommitted": "110",
"suppress": false
},
{
"id": 10,
"orderNo": "0000102692",
"sequence": 3,
"inventory": {
"id": 33,
"whse": "VA",
"partNo": "SPAB",
"description": "Springfield Ab Toner"
},
"serials": null,
"whse": "VA",
"partNo": "SPAB",
"description": "Springfield Ab Toner",
"comment": "",
"orderQty": "1",
"committedQty": "1",
"backorderQty": "0",
"retailPrice": "45",
"unitPrice": "45",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "SPRFIT",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "45",
"extendedPriceCommitted": "45",
"suppress": false
},
{
"id": 11,
"orderNo": "0000102692",
"sequence": 4,
"inventory": {
"id": 46,
"whse": "VA",
"partNo": "INSDB50",
"description": "InSpire Dumbbell 50"
},
"serials": null,
"whse": "VA",
"partNo": "INSDB50",
"description": "InSpire Dumbbell 50",
"comment": "",
"orderQty": "2",
"committedQty": "2",
"backorderQty": "0",
"retailPrice": "118",
"unitPrice": "118",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "INSPIRE",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "236",
"extendedPriceCommitted": "236",
"suppress": false
},
{
"id": 12,
"orderNo": "0000102692",
"sequence": 5,
"inventory": {
"id": 42,
"whse": "VA",
"partNo": "INSDB15",
"description": "InSpire Dumbbell 15"
},
"serials": null,
"whse": "VA",
"partNo": "INSDB15",
"description": "InSpire Dumbbell 15",
"comment": "",
"orderQty": "3",
"committedQty": "3",
"backorderQty": "0",
"retailPrice": "34",
"unitPrice": "34",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "INSPIRE",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "102",
"extendedPriceCommitted": "102",
"suppress": false
},
{
"id": 13,
"orderNo": "0000102692",
"sequence": 6,
"inventory": {
"id": 9,
"whse": "VA",
"partNo": "INSWP50",
"description": "InSpire Weight Plate 50"
},
"serials": null,
"whse": "VA",
"partNo": "INSWP50",
"description": "InSpire Weight Plate 50",
"comment": "",
"orderQty": "1",
"committedQty": "1",
"backorderQty": "0",
"retailPrice": "66",
"unitPrice": "66",
"discountable": true,
"discountPct": "0",
"discountAmt": "0",
"taxFlags": [
true,
true,
false,
false
],
"sellMeasure": "EA",
"vendor": "INSPIRE",
"levyCode": "",
"requiredDate": "2015-08-26",
"extendedPriceOrdered": "66",
"extendedPriceCommitted": "66",
"suppress": false
}
],
"payments": [
],
"createdBy": "SS",
"modifiedBy": "SS",
"created": "2014-08-26T11:44:57.930000",
"modified": "2015-02-20T08:09:55",
"links": {
"notes": "https://localhost:10880/api/v2/companies/INSPIRE/sales/orders/7/notes/"
}
}
EDIT 2
Answer by Erik A showed me how parsing can be done on-demand or 'streaming'. The parsing is only done when you ask for the element.
I think I have misunderstood the nature of how VB.NET deserializes JSON. It must be doing the same thing. So when I saw 500 ms instead of 18 seconds I didn't know what I was looking at. I suspect that if I walked through the de-serialized json in VB.NET and inspected every element, it would take much longer. My sample data for performance testing was actually a collection of 124 of the JSON sample, some with a lot more ITEMS, hence the 18 seconds. Is this correct?
Albert's answer showed me something I wanted to do originally, but couldn't get it to work. Great complete answer I will be digging into next.