编程语言
首页 > 编程语言> > javascript – JSON.Stringify在Scripting.Dictionary对象上失败

javascript – JSON.Stringify在Scripting.Dictionary对象上失败

作者:互联网

我正在开发一个ASP经典项目,我已经实现了here的JScript JSON类.它能够与VBScript和JScript互操作,几乎完全是json.org提供的代码.我需要使用VBScript来完成这个项目.我的团队经理.

它在ASP中定义的基元和类上非常有效.但是我需要Dictionary对象,据我所知,这些对象只能通过COM interop获得. (通过Server.CreateObject(“Scripting.Dictionary”))我有以下代表产品的类:(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
%>

Specs属性是键:值对的字典.这是我如何序列化它:(product.asp)

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

当我将ProductInfo的实例传递给JSON.Stringify时(如上所示),我得到如下内容:

{
    "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": {}
}

如您所见,Specs属性是一个空对象.我相信JSON stringify方法知道Specs属性是一个对象,因此它将{}附加到字符串化输出周围的JSON字符串.在这种情况下,这是一个空字符串.我希望它展示的不是一个空的对象.见下文:

"Specs": {
    "foo":"bar",
    "baz":1,
    "etc":"..."
}

我相信JSON库的问题区域在这里:(json2.asp)

// Otherwise, iterate through all of the keys in the object.

for (k in value) {
    if (Object.hasOwnProperty.call(value, k)) {
        v = str(k, value);
        if (v) {
            partial.push(quote(k) + (gap ? ': ' : ':') + v);
        }
    }
}

我假设上面代码的问题是它假定所有对象都继承自Object类. (提供hasOwnProperty的那个)但是我认为COM对象可能不会从Object类继承 – 或者至少是相同的Object类.或者至少不要在它们上面实现所需的任何接口.

更新:虽然我认为这个问题无法解决 – 我希望某种Web客户端可以请求(通过http)此对象的JSON表示或此对象的集合.

tl; dr问题:我应该怎么做才能使Scripting.Dictionary能够正确输出为JSON而不是失败并返回一个空字符串?我是否需要’重新发明轮子’并在VBScript中编写我自己的Dictionary类,它在ASP中作为普通对象?

解决方法:

构造中的Javascript for …(在您引用的JSON序列化程序中使用)仅适用于本机JS对象.要枚举Scripting.Dictionary的键,您需要使用Enumerator对象,它将枚举Dictionary的键.

现在,通过检查每个属性上是否存在toJSON方法,JSON.stringify方法有一种允许自定义序列化的好方法.不幸的是,您无法像在原生JS对象上那样在现有COM对象上添加新方法,因此这是不行的.

然后是自定义字符串化函数,可以作为第二个参数传递给stringify方法调用.即使对于每个嵌套对象,也会为需要进行字符串化的每个对象调用该函数.我认为可以在这里使用.

一个问题是(AFAIK)JScript无法区分VBScript类型.对于JScript,任何COM或VBScript对象都具有typeof ===’object’.我知道获取该信息的唯一方法是定义将返回类型名称的VBS函数.

由于经典ASP文件的执行顺序如下:

>< script>使用非默认脚本语言的块(在您的情况下,JScript)
>< script>使用默认脚本语言的块(在您的情况下,VBScript)
><%...%>块,使用默认的脚本语言(在您的情况下,VBScript)

以下方法可行 – 但仅当JSON.stringify调用在<%...%>内完成时括号,因为这是JScript和VBScript< script>的唯一时间.部分都将被解析和执行.

最后的函数调用是这样的:

<%
    Response.Write JSON.stringify(oProd, vbsStringifier)
%>

为了让JScript检查COM对象的类型,我们定义了一个VBSTypeName函数:

<script language="VBScript" runat="server">
    Function VBSTypeName(Obj)
        VBSTypeName = TypeName(Obj)
    End Function
</script>

在这里,我们将vbsStringifier的完整实现作为第二个参数传递给JSON.stringify:

<script language="JScript" runat="server">

    function vbsStringifier(holder, key, value) {
        if (VBSTypeName(value) === 'Dictionary') {
            var result = '{';
            for(var enr = new Enumerator(value); !enr.atEnd(); enr.moveNext()) {
                key = enr.item();
                result += '"' + key + '": ' + JSON.stringify(value.Item(key));
            }
            result += '}';
            return result;
        } else {
        // return the value to let it be processed in the usual way
            return value;
        }
    }

</script>

当然,在脚本引擎之间来回切换效率不高(即从JS调用VBS函数,反之亦然),因此您可能希望尽量将其保持在最低限度.

另请注意,由于我的计算机上不再有IIS,因此无法对此进行测试.基本原理应该有效,我不是100%肯定从VBScript传递JScript函数引用的可能性.您可能必须为JScript中的JSON.stringify调用编写一个小的自定义包装函数:

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

之后你可以简单地调整VBScript调用:

<%
    Response.Write JSONStringify(oProd)
%>

标签:javascript,json,vbscript,com,asp-classic
来源: https://codeday.me/bug/20191007/1864977.html