Attempting to utilize JSON.Stringify on Scripting.Dictionary objects will result in failure

In my current ASP classic project, I have integrated the JScript JSON class available at this link. This class can interact with both VBScript and JScript, closely resembling the code provided on json.org. However, due to team manager's requirement, I must utilize VBScript for this project.

The JSON parsing works well for primitives and classes defined within ASP. But now, I need to incorporate Dictionary objects, which as far as I know, are only accessible through COM interop (using

Server.CreateObject("Scripting.Dictionary")
). I have a class named ProductInfo that represents a product in the following structure: (ProductInfo.class.asp)

<%
Class ProductInfo

    Public ID
    Public Category
    Public PriceUS
    Public PriceCA
    Public Name
    Public SKU
    Public Overview
    Public Features
    Public Specs

End Class
%>

The Specs property within ProductInfo is a Dictionary of key-value pairs. Here's how I attempt to serialize it: (product.asp)

<%
dim oProd
set oProd = new ProductInfo
' ... fill in properties
' ... output appropriate headers and stuff
Response.write( JSON.stringify( oProd ) )
%>

When passing an instance of ProductInfo to JSON.Stringify, the resulting JSON contains an empty object for the Specs property:

{
    "id": "1547",
    "Category": {
        "id": 101,
        "Name": "Category Name",
        "AlternateName": "",
        "URL": "/category_name/",
        "ParentCategoryID": 21
    },
    "PriceUS": 9.99,
    "PriceCA": 11.99,
    "Name": "Product Name",
    "SKU": 3454536,
    "Overview": "Lorem Ipsum dolor sit amet..",
    "Features": "Lorem Ipsum dolor sit amet..",
    "Specs": {}
}

Instead of an empty object, I would like the JSON to display actual key-value pairs for Specs. My assumption is that the issue lies within the JSON library implementation (json2.asp).

After analyzing the code snippet where the problem might occur, it seems to me that the library assumes all objects inherit from the Object class, which may not be true for COM objects used in ASP.

Update: Although the specifics might not impact the answer, I anticipate a web client fetching the JSON representation of this object or a collection thereof via HTTP.

tl;dr The question: How can I ensure that Scripting.Dictionary outputs correctly as JSON without returning an empty string? Would creating a custom Dictionary class in VBScript be necessary for it to behave like a standard object in ASP?

Answer №1

When working with Javascript's for...in construct to serialize JSON data, keep in mind that it only works on native JS objects. If you need to enumerate the keys of a Scripting.Dictionary, you'll need to use an Enumerator object specifically designed for Dictionary.

Custom serialization can be achieved using the JSON.stringify method by checking for a toJSON method on each property. However, adding new methods to existing COM objects like VBScript objects is not possible in the same way as with native JS objects.

You can pass a custom stringifier function as the second argument to the stringify method, which will be called for each object that needs to be serialized, including nested objects.

A challenge arises when JScript cannot differentiate between different VBScript types natively. To overcome this limitation, define a VBS function that returns the type name of a given object.

To ensure successful execution order in classic ASP files where both JScript and VBScript are used, place the JSON.stringify call within <% ... %> brackets after all script blocks have been parsed and executed.

For efficient implementation, create a VBSTypeName function in VBScript to check the type of a COM object, and implement the vbsStringifier function in JScript to handle serialization accordingly. Minimize switching between scripting engines for better performance.


Note: Testing may be required as IIS environment is needed for verification. Consider wrapping the JSON.stringify call in a custom JScript function reference if passing functions between scripting engines proves challenging:

<script runat="server" language="JScript">
    function JSONStringify(object) {
        return JSON.stringify(object, vbsStringifier);
    }
</script>

Adjust the VBScript call accordingly:

<%
    Response.Write JSONStringify(oProd)
%>

Answer №2

I wrote a personalized function for serializing Dictionary types, but it may require manual find and replace for unsuccessful dictionary serializations. ({}) Unfortunately, I haven't found an automated solution yet. Feel free to fork it on BitBucket.

Function stringifyDictionary( key, value, sp )

  dim str, val

  Select Case TypeName( sp )
    Case "String"
      sp = vbCrLf & sp
    Case "Integer"
      sp = vbCrLf & Space(sp)
    Case Else
      sp = ""
  End Select

  If TypeName( value ) = "Dictionary" Then
    str = """" & key & """:{" & sp
    For Each k in value
      val = value.Item(k)
      If Not Right(str, 1+len(sp)) = "{" & sp And Not Right(str, 1+len(sp)) = "," & sp Then
        str = str & "," & sp
      End If
      str = str & """" & k & """: "
      If TypeName( val ) = "String" Then
        If val = "" Then
          str = str & "null"
        Else
          str = str & """" & escapeJSONString( val ) & """"
        End If
      Else
        str = str & CStr( val )
      End If
    Next
    str = str & sp & "}"
    stringifyDictionary = str
  Else
    stringifyDictionary = value
  End If

End Function

Function escapeJSONString( str )
  escapeJSONString = replace(replace(str, "\", "\\"), """", "\""")
End Function

This function was created specifically for use with JSON.stringify's replace argument (2nd arg). However, passing a VBScript function as an argument is not possible (based on my experience). If you rewrite this function in JScript, you can utilize it when calling JSON.stringify to ensure proper rendering of Dictionaries. For more details, refer to the readme on BitBucket. Here's how it was implemented:

dim spaces: spaces = 2
dim prodJSON: prodJSON = JSON.stringify( oProduct, Nothing, spaces)
prodJSON = replace(prodJSON, """Specs"": {}", stringifyDictionary("Specs", oProduct.Specs, spaces * 2))

Known issues:

  • The closing } for the Dictionary serialization will have the same number of indentations as the properties it contains. Exploring alternative solutions would require adding another argument, which was not pursued.

Answer №3

JSON does not contain any inherent type information. The beauty of JSON lies in its ability to represent a wide range of data structures, whether it be an object or an array of values. These objects can have various named properties consisting of strings and values that include null, true, false, numbers, strings, objects, or arrays.

The process of how this data structure is implemented in different programming languages is left up to you. For instance, when converting JSON to Java, one may choose to use ArrayList for arrays, HashMap for objects, and native types for simpler values. However, there may be cases where you prefer the objects to align with specific Java bean classes. In such instances, the JSON parser will need guidance on which objects to instantiate, a process that varies depending on the JSON parser and its APIs.

(edit — my previous statement about "no type information at all" referred specifically to "object" values; it's evident that booleans, strings, and numbers do have discernible types.)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for seamless communication between PHP and JavaScript

While working on my revolutionary WebIDE, I encounter numerous questions that challenge me. The goal of this project is to assist users in quickly developing what they normally would, but automated. One particular question I have is regarding the implement ...

"Enhance Your Website with Bootstrap Modal and Jazz up Your

I am encountering an issue with modal-bootatrap and bootstrap-datepicker. Within the datatable, there is a button provided for editing. Upon clicking the edit button, a modal-bootstrap will be displayed. The modal-bootstrap contains a form for editing d ...

Facebook sharing woes: Angular app's OG meta tags fail to work properly

Trying to figure out how to properly use og tags for the first time. I'm working on an Angular application and need to share my app link on Facebook with all the necessary tag information included. In my index.html file, I've inserted the follow ...

What is the way to create the appearance of a hand or arrow hovering over my "X" while I am closing out my Div using jQuery?

Hey there, I've got a handle on closing the div using a "p" tag in jQuery. The code snippet for that is provided below. However, I'm looking to change the cursor over the "X" to an arrow or hand symbol, similar to what you'd see with an "a" ...

Exploring the intricacies of ODATA SAPUI5 mockup with nested JSON structures

Having a challenge with accessing nested data from a JSON file used as mockup data in an ODATA SAPUI5 application. Below is the JSON content: [{ "testcase": { "specification": "SRS PR 28717 – Deposit in Brazilian Reais", "execution": { ...

Error encountered: The EVM has reverted the transaction

After successfully deploying this basic smart contract using Remix, I encountered an issue when trying to interact with it through web3.js in my upcoming app. I used the evm version: paris for deployment and everything worked smoothly on Remix IDE. Here i ...

Converting unstructured text to JSON format

I am facing a challenge with a string that appears as follows: {"name": "john", "smith", "paul", "address": "nyc", "chicago", "age": 50, 60} My objective is to transform this into JSON in the following format: {"name": ["john", "smith", "paul"], "addres ...

How to link a CSS file from a JavaScript file

I have a form for users with fields for first name, last name, password, and confirm password. I've implemented validation to check if the password and confirm password fields match using JavaScript: $(document).ready(function() { $("#addUser").cl ...

Transferring information between two resolvers within the same route in Angular

Can data be transferred from one resolver to another on the same route? { path: 'book-view/:id', component: BookViewComponent, resolve: { book: BookViewResolver, user: UserResolver } } For example, if I need to p ...

Child object in Three.js does not inherit transformation from its parent

Consider a scenario where there is a main object with multiple child objects in a given scene. Update: Here is the code snippet for creating a mesh (assuming the scene and camera are already set up). Code snippet for creating the parent group: var geome ...

How to include a new variable within a JSON string using C#

I have been working on some code to make it more dynamic. Originally, I used a hardcoded ID in my json string to post a new object with NUnit Test Project using RestSharp. Now, I am attempting to remove the hardcoded object ID and replace it with an empt ...

Configuring Google Maps API (including charts) for maximum height of 100%

I am having trouble getting my map to display at 100% height using the Google Maps API. I've encountered similar issues in the past with the Google Charts API as well. From what I've gathered, it seems like setting the height of the html and bod ...

Unable to modify preset choices in radio checkboxes

I am a paramedic with no prior experience in this area. My task involves completing numerous patient forms that contain excessive fields, creating redundancy. To streamline this process, I am attempting to script a solution that will automatically populat ...

Issue with locating JavaScript controller in Angular HTML file [Node.js/Angular]

Here are all the files and folders in my project located within the same directory. If you want to check out the project on Github, you can find it here: https://github.com/JohnsCurry/learnAngular. Just to confirm, they are all in the same folder. Unfortu ...

Behind the scenes, unable to launch due to Schema Error

My experience with Backstage was going smoothly until I ran into an issue after executing a yarn install this afternoon. Now, whenever I attempt to run yarn dev, it fails with the following error: [0] Loaded config from app-config.yaml [0] <i> [webpa ...

Utilizing a JavaScript variable to fetch a rails URL: A comprehensive guide

One interesting feature I have is an image link that has a unique appearance: <a href="#user-image-modal" data-toggle="modal" data-id="<%= image.id %>"><img class="user-photo" src="<%= image.picture.medium.url %>" alt="" /></a&g ...

What is the best way to categorize a collection of objects within a string based on their distinct properties?

I am working with an array of hundreds of objects in JavaScript, each object follows this structure : object1 = { objectClass : Car, parentClass : Vehicle, name : BMW } object2 = { objectClass : Bicycle, parentClass : Vehicle, name : Giant } object3 = { ob ...

Cypress and Cucumber collaborate to reinitialize the requests within Next Js

In my upcoming project with Next.js, I am utilizing Cypress for testing a specific page. The objective is to validate two scenarios: 1. Successful outcome and 2. Error handling when a user encounters an issue. Before(() => { return void cy.server() ...

Deleting a file and value in JavaScript

Can you help me figure out how to remove the value of q when the .close class is clicked? Here's my code: $(document).on('click', '.close', function () { $(this).parents('p').remove(); }) $('#Q1DocPath'). ...

Difficulty in adding a simple return to render an array in React for list creation

After establishing a basic object, I noticed that it contained an internal object named "orders" with an array of toppings like "Cheese" and "Bacon". To further explore this structure, I segregated the array and directed it to a function called renderToppi ...