JSON.Stringify fails on Scripting.Dictionary objects(JSON.Stringify 在 Scripting.Dictionary 对象上失败)
问题描述
我正在开发一个 ASP 经典项目,我在其中实现了找到的 JScript JSON 类 这里.它能够与 VBScript 和 JScript 互操作,并且几乎完全是 json.org 提供的代码.我的团队经理要求我在这个项目中使用 VBScript.
I am working on an ASP classic project where I have implemented the JScript JSON class found here. It is able to interop with both VBScript and JScript and is almost exactly the code provided at json.org. I am required to use VBScript for this project by the manager of my team.
它在 ASP 中定义的原语和类上工作得很好.但我需要 Dictionary 对象,据我所知,这些对象只能通过 COM 互操作获得.(通过 Server.CreateObject("Scripting.Dictionary")
)我有以下代表产品的类:(ProductInfo.class.asp)
It works very well on primitives and classes defined within ASP. But I have need for Dictionary objects which from my knowledge are only available through COM interop. (via Server.CreateObject("Scripting.Dictionary")
) I have the following class which represents a product: (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)
The Specs
property is a Dictionary of key:value pairs. Here's how I'm serializing it: (product.asp)
<%
dim oProd
set oProd = new ProductInfo
' ... fill in properties
' ... output appropriate headers and stuff
Response.write( JSON.stringify( oProd ) )
%>
当我将 ProductInfo
的实例传递给 JSON.Stringify
(如上所示)时,我得到如下内容:
When I pass an instance of ProductInfo
to JSON.Stringify
(as seen above) I get something like the following:
{
"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
属性是一个对象,因此它将 {}
附加到 stringified 周围的 JSON 字符串输出.在这种情况下是一个空字符串.然而,我期望它显示的不是一个空对象.见下文:
As you can see, the Specs
property is an empty object. I believe that the JSON stringify method knows that the Specs
property is an object, so it appends the {}
to the JSON string around the stringified output. Which in this case is an empty string. What I expect it to show, however is not an empty object. See below:
"Specs": {
"foo":"bar",
"baz":1,
"etc":"..."
}
相信JSON库的问题区域在这里:(json2.asp)
I believe the problem area of the JSON library is here: (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
类继承的 —或者至少是 same Object
类.或者至少不要实现对它们执行 for ... in
所需的任何接口.
I postulate that the problem with the above code is that it assumes that all objects inherit from the Object
class. (The one that provides hasOwnProperty
) However I think that it's likely that COM objects don't inherit from the Object
class — or at least the same Object
class. Or at least don't implement whatever interface is required to do for ... in
on them.
更新:虽然我觉得回答这个问题无关紧要——我希望某种 Web 客户端(通过 http)请求该对象的 JSON 表示或该对象的集合.
Update: While I feel it is irrelevant for the question to be answered — I expect some sort of web client to request (via http) the JSON representation of this object or a collection of this object.
tl;dr 问题:我应该怎么做才能使 Scripting.Dictionary
可以正确输出为 JSON 而不是失败并仅返回一个空细绳?我是否需要重新发明轮子"并在 VBScript 中编写自己的 Dictionary
类 在 ASP 中充当普通对象?
tl;dr The question: What should I do to make it so that the Scripting.Dictionary
can be output properly as JSON instead of failing and returning just an empty string? Do I need to 'reinvent the wheel' and write my own Dictionary
class in VBScript that does act as a normal object in ASP?
推荐答案
Javascript 的 for...in
构造(在你提到的 JSON 序列化器中使用)仅适用于原生 JS 对象.要枚举 Scripting.Dictionary
的键,您需要使用 Enumerator 对象,它将枚举 Dictionary 的键.
Javascript’s for...in
construct (which is used in the JSON serializer you refer to) only works on native JS objects. To enumerate a Scripting.Dictionary
’s keys, you need to use an Enumerator object, which will enumerate the keys of the Dictionary.
现在,JSON.stringify
方法有一种允许自定义序列化的好方法,通过检查每个属性上是否存在 toJSON
方法.不幸的是,您不能像在本机 JS 对象上那样在现有 COM 对象上添加新方法,所以这是不行的.
Now the JSON.stringify
method has a nifty way of allowing custom serialization, by checking for the presence of a toJSON
method on each property. Unfortunately, you can’t tack new methods on existing COM objects the way you can on native JS objects, so that’s a no-go.
然后是自定义字符串化函数,它可以作为第二个参数传递给 stringify
方法调用.将为每个需要字符串化的对象调用该函数,即使对于每个嵌套对象也是如此.我认为可以在这里使用.
Then there’s the custom stringifier function that can be passed as second argument to the stringify
method call. That function will be called for each object that needs to be stringified, even for each nested object. I think that could be used here.
一个问题是(AFAIK)JScript 无法自行区分 VBScript 类型.对于 JScript,任何 COM 或 VBScript 对象都有 typeof === 'object'
.我知道获取该信息的唯一方法是定义一个返回类型名称的 VBS 函数.
One problem is that (AFAIK) JScript is unable to differentiate VBScript types on its own. To JScript, any COM or VBScript object has typeof === 'object'
. The only way I know of getting that information across, is defining a VBS function that will return the type name.
由于经典ASP文件的执行顺序如下:
Since the execution order for classic ASP files is as follows:
<script>
具有非默认脚本语言(在您的情况下为 JScript)的块<script>
具有默认脚本语言(在您的情况下为 VBScript)的块<% ... %>
块,使用默认脚本语言(在您的情况下为 VBScript)
<script>
blocks with non-default script languages (in your case, JScript)<script>
blocks with the default script language (in your case, VBScript)<% ... %>
blocks, using the default script language (in your case, VBScript)
以下方法可以工作——但仅当 JSON.stringify
调用在 <% ... %>
括号内完成,因为这是唯一一次同时解析和执行 JScript 和 VBScript <script>
部分.
The following could work — but only when the JSON.stringify
call is done within <% ... %>
brackets, since that’s the only time when both JScript and VBScript <script>
sections would both have been parsed and executed.
最终的函数调用是这样的:
The final function call would be this:
<%
Response.Write JSON.stringify(oProd, vbsStringifier)
%>
为了让 JScript 能够检查 COM 对象的类型,我们定义了一个 VBSTypeName 函数:
In order to allow JScript to check the type of a COM object, we'd define a VBSTypeName function:
<script language="VBScript" runat="server">
Function VBSTypeName(Obj)
VBSTypeName = TypeName(Obj)
End Function
</script>
这里我们有了 vbsStringifier 的完整实现,它作为第二个参数传递给 JSON.stringify:
And here we have the full implementation of the vbsStringifier that is passed along as second parameter to 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 函数,反之亦然),因此您可能希望尽量减少这种情况.
Of course, switching back and forth between scripting engines isn’t very efficient (i.e. calling a VBS function from JS and vice versa), so you probably want to try to keep that to a minimum.
另外请注意,我无法对此进行测试,因为我的机器上不再有 IIS.基本原理应该有效,我不能 100% 确定从 VBScript 传递 JScript 函数引用的可能性.您可能需要为 JScript 中的 JSON.stringify 调用编写一个小的自定义包装函数:
Also note that I haven’t been able to test this, since I no longer have IIS on my machine. The basic principle should work, I’m not 100% certain of the possibility to pass a JScript function reference from VBScript. You might have to write a small custom wrapper function for the JSON.stringify call in JScript:
<script runat="server" language="JScript">
function JSONStringify(object) {
return JSON.stringify(object, vbsStringifier);
}
</script>
之后您可以简单地调整 VBScript 调用:
after which you can simply adjust the VBScript call:
<%
Response.Write JSONStringify(oProd)
%>
这篇关于JSON.Stringify 在 Scripting.Dictionary 对象上失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:JSON.Stringify 在 Scripting.Dictionary 对象上失败
基础教程推荐
- 如何使用TypeScrip将固定承诺数组中的项设置为可选 2022-01-01
- 如何使用JIT在顺风css中使用布局变体? 2022-01-01
- 自定义 XMLHttpRequest.prototype.open 2022-01-01
- 我可以在浏览器中与Babel一起使用ES模块,而不捆绑我的代码吗? 2022-01-01
- Electron 将 Node.js 和 Chromium 上下文结合起来意味着 2022-01-01
- 用于 Twitter 小部件宽度的 HTML/CSS 2022-01-01
- html表格如何通过更改悬停边框来突出显示列? 2022-01-01
- Vue 3 – <过渡>渲染不能动画的非元素根节点 2022-01-01
- Chart.js 在线性图表上拖动点 2022-01-01
- 直接将值设置为滑块 2022-01-01