需要在 ExtendScript 中对对象进行 JSON 字符串化 [英] Need to JSON stringify an object in ExtendScript

查看:20
本文介绍了需要在 ExtendScript 中对对象进行 JSON 字符串化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ExtentdScript 处理 Indesign 文档链接的元数据信息.

我想使用 JSON.stringify 将对象转换为字符串,但是当我使用它时,我收到错误消息:

<块引用>

无法在目标引擎中执行脚本.

如果我从下面的代码中删除 linkObjStr = JSON.stringify(linksInfoObj);,那么一切正常.

ExtendScript 中的 JSON.stringify 等价物是什么,或者是否有任何其他可能性来显示 linksInfoObj 及其正确的内容而不是 [object object]?

for (var i = 0, len = doc.links.length; i < len; i++) {var linkFilepath = File(doc.links[i].filePath).fsName;var linkFileName = doc.links[i].name;var xmpFile = new XMPFile(linkFilepath, XMPConst.FILE_INDESIGN, XMPConst.OPEN_FOR_READ);var allXMP = xmpFile.getXMP();//从外部链接中检索值 XMP.var documentID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'DocumentID', XMPConst.STRING);var instanceID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'InstanceID', XMPConst.STRING);linksInfoObj[linkFileName] = {'docId': documentID, 'insId': instanceID};linkObjStr = JSON.stringify(linksInfoObj);alert('Object' + linksInfoObj, true);//我在这里得到 [Object Object]alert('String' + linkObjStr, true);}

解决方案

ExtendScript 不包含具有相关解析方法的 JSON 对象,即 JSON.parse()JSON.字符串化().它也不提供用于解析 JSON 的任何其他内置功能.<​​/p>


解决方案:

考虑使用 polyfill 来提供 JSON 功能,例如 JSON-js 由 Douglas Crockford 创建.

您需要做的事情:

  1. 下载名为 json2.js 来自 Github 存储库并将其保存在与 .jsx 文件相同的位置/文件夹中.

    注意您只需复制并粘贴来自同一个 Github 存储库的 json2.js 的原始版本,如果您愿意,可以手动创建 json2.js 文件.

  2. 然后在当前 .jsx 文件的顶部,您需要通过 #include json2.js 文件添加以下代码行:

     #include "json2.js";

    这类似于您如何使用 import 语句以在现代 JavaScript (ES6) 中包含一个模块.

    如果您决定将文件保存在与 .jsx 不同的位置/文件夹中,则可以提供 json2.js 位置的

    路径名 文件.

  3. 通过在您的 .jsx 文件中包含 json2.js,您现在将拥有可用的 JSON 方法;JSON.parse()JSON.stringify().


示例:

以下 ExtendScript (.jsx) 是一个工作示例,它生成 JSON 以指示与当前 InDesign 文档 (.indd) 关联的所有链接.

example.jsx

#include "json2.js";$.level=0;var doc = app.activeDocument;/*** 加载 Adob​​eXMPScript 库.* @returns {Boolean} 如果库加载成功,则为真,否则为假.*/函数 loadXMPLibrary() {如果 (!ExternalObject.AdobeXMPScript) {尝试 {ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');}赶上(e){alert('加载 Adob​​eXMPScript 库失败\n' + e.message, '错误', true);返回假;}}返回真;}/*** 获取`DocumentID` 和`instanceID` 的XMP 属性值* 每个与 InDesign 文档 (.indd) 关联的链接文件.A 返回* 信息格式为 JSON,* @param {Object} doc - 对要检查的 .indd 的引用.* @returns {String} - JSON 格式的信息.*/函数 getLinksInfoAsJson(doc) {var linksInfoObj = {};linksInfoObj['indd-name'] = doc.name;linksInfoObj.location = doc.filePath.fsName;linksInfoObj.links = [];for (var i = 0, len = doc.links.length; i < len; i++) {var linkFilepath = File(doc.links[i].filePath).fsName;var linkFileName = doc.links[i].name;var xmpFile = new XMPFile(linkFilepath, XMPConst.FILE_INDESIGN, XMPConst.OPEN_FOR_READ);var allXMP = xmpFile.getXMP();//从外部链接中检索值 XMP.var documentID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'DocumentID', XMPConst.STRING);var instanceID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'InstanceID', XMPConst.STRING);//确保我们生成有效的 JSON...//- 当 `instanceID` 或 `documentID` 值等于 `undefined` 时更改为 `null`.//- 当 `instanceID` 或 `documentID` 存在时,确保它是一个字符串.实例 ID = 实例 ID ?字符串(实例ID):空;文档 ID = 文档 ID ?字符串(文档ID):空;linksInfoObj.links.push({'name':链接文件名,路径":链接文件路径,'docId':文档ID,'insId':实例ID});}返回 JSON.stringify(linksInfoObj, null, 2);}如果(loadXMPLibrary()){var linksJson = getLinksInfoAsJson(doc);$.writeln(linksJson);}

输出:

运行上面的脚本会将类似于以下示例的 JSON 格式记录到您的控制台:

{indd-name":foobar.indd",位置":/path/to/the/document",链接":[{名称":one.psd",路径":/path/to/the/document/links/one.psd",docId":5E3AE91C0E2AD0A57A0318E078A125D6",insId":xmp.iid:0480117407206811AFFD9EEDCD311C32"},{名称":two.jpg",路径":/path/to/the/document/links/two.jpg",docId":EDC4CCF902ED087F654B6AB54C57A833",insId":xmp.iid:FE7F117407206811A61394AAF02B0DD6"},{名称":三个.png",路径":/path/to/the/document/links/three.png",docId":空,insId":空}]}


旁注:建模您的 JSON:

您会注意到 JSON 输出(上图)的结构与您在给定示例中尝试构建它的方式不同.主要区别在于您使用链接文件名作为属性/键名,例如以下示例:

有问题的 JSON 结构示例

{一个.psd":{docId":5E3AE91C0E2AD0A57A0318E078A125D6",insId":xmp.iid:0480117407206811AFFD9EEDCD311C32"},两个.jpg":{docId":EDC4CCF902ED087F654B6AB54C57A833",insId":xmp.iid:FE7F117407206811A61394AAF02B0DD6"}...}

像这个例子那样生成 JSON 并不理想,因为如果你有两个链接,它们都具有相同的名称,你只会报告其中一个.一个对象中不能有两个同名的属性/键.


作为对 OP 评论的回应:

<块引用>

您好 RobC,除了使用 #include 'json2.js' 之外,还有其他方法可以在 JSX 文件中包含外部 js 文件吗?

有以下几种替代方法:

  1. 你可以使用 $.evalFile().例如,将 #include "json2.js"; 替换为以下两行:

     var json2 = File($.fileName).path + "/";+ "json2.js";$.evalFile(json2);

    注意:此示例假设 json2.js 与您的 .jsx

    位于同一文件夹中
  2. 或者,如果您想完全避免额外的 json2.js 文件的存在.您可以在顶部添加 IIFE(立即调用的函数表达式)你的 .jsx 文件.然后将 json2.js 文件的内容复制并粘贴到它.例如:

     (function () {//<-- 在这里粘贴`json2.js`的内容.})();

    注意:如果代码大小是一个问题,那么考虑缩小 json2.js 的内容,然后将其粘贴到 IIFE 中.

I am working on processing meta data information of my Indesign document links, using ExtentdScript.

I want to convert the object to string using JSON.stringify but when I use it, I am getting error saying:

can't execute script in target engine.

If I remove linkObjStr = JSON.stringify(linksInfObj); from below code, then everything works fine.

What is the equivalent to JSON.stringify in ExtendScript, or is there any other possibilities to display linksInfObj with its proper contents instead [object object]?

for (var i = 0, len = doc.links.length; i < len; i++) {

    var linkFilepath = File(doc.links[i].filePath).fsName;
    var linkFileName = doc.links[i].name;

    var xmpFile = new XMPFile(linkFilepath, XMPConst.FILE_INDESIGN, XMPConst.OPEN_FOR_READ);
    var allXMP = xmpFile.getXMP();

    // Retrieve values from external links XMP.
    var documentID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'DocumentID', XMPConst.STRING);
    var instanceID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'InstanceID', XMPConst.STRING);
    linksInfObj[linkFileName] = {'docId': documentID, 'insId': instanceID};
    linkObjStr = JSON.stringify(linksInfObj);

    alert('Object' + linksInfObj, true); // I am getting [Object Object] here
    alert('String' + linkObjStr, true);

}

解决方案

ExtendScript does not include a JSON object with the associated methods for parsing, namely JSON.parse() and JSON.stringify(). Nor does it provide any other builtin feature for parsing JSON.


Solution:

Consider utilizing a polyfill to provide JSON functionality such as JSON-js created by Douglas Crockford.

What you'll need to do:

  1. Download the JavaScript file named json2.js from the Github repo and save it in the same location/folder as your .jsx file.

    Note You can just copy and paste the raw version of json2.js from the same Github repo to create the json2.js file manually if you prefer.

  2. Then at the top of your current .jsx file you'll need to #include the json2.js file by adding the following line of code:

     #include "json2.js";
    

    This is analogous to how you might utilize the import statement to include a module in modern day JavaScript (ES6).

    A pathname to the location of the json2.js can be provided if you decide to save the file in a different location/folder than your .jsx file.

  3. By including json2.js in your .jsx file you'll now have working JSON methods; JSON.parse() and JSON.stringify().


Example:

The following ExtendScript (.jsx) is a working example that generates JSON to indicate all the links associated with the current InDesign document (.indd).

example.jsx

#include "json2.js";

$.level=0;

var doc = app.activeDocument;

/**
 * Loads the AdobeXMPScript library.
 * @returns {Boolean} True if the library loaded successfully, otherwise false.
 */
function loadXMPLibrary() {
  if (!ExternalObject.AdobeXMPScript) {
    try {
      ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
    } catch (e) {
      alert('Failed loading AdobeXMPScript library\n' + e.message, 'Error', true);
      return false;
    }
  }
  return true;
}

/**
 * Obtains the values f XMP properties for `DocumentID` and `instanceID` in
 * each linked file associated with an InDesign document (.indd). A returns the
 * information formatted as JSON,
 * @param {Object} doc - A reference to the .indd to check.
 * @returns {String} - The information formatted as JSON.
 */
function getLinksInfoAsJson(doc) {
  var linksInfObj = {};

  linksInfObj['indd-name'] = doc.name;
  linksInfObj.location = doc.filePath.fsName;
  linksInfObj.links = [];

  for (var i = 0, len = doc.links.length; i < len; i++) {
    var linkFilepath = File(doc.links[i].filePath).fsName;
    var linkFileName = doc.links[i].name;

    var xmpFile = new XMPFile(linkFilepath, XMPConst.FILE_INDESIGN, XMPConst.OPEN_FOR_READ);
    var allXMP = xmpFile.getXMP();

    // Retrieve values from external links XMP.
    var documentID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'DocumentID', XMPConst.STRING);
    var instanceID = allXMP.getProperty(XMPConst.NS_XMP_MM, 'InstanceID', XMPConst.STRING);

    // Ensure we produce valid JSON...
    // - When `instanceID` or `documentID` values equal `undefined` change to `null`.
    // - When `instanceID` or `documentID` exist ensure it's a String.
    instanceID = instanceID ? String(instanceID) : null;
    documentID = documentID ? String(documentID) : null;

    linksInfObj.links.push({
      'name': linkFileName,
      'path': linkFilepath,
      'docId': documentID,
      'insId': instanceID
    });
  }

  return JSON.stringify(linksInfObj, null, 2);
}

if (loadXMPLibrary()) {
 var linksJson = getLinksInfoAsJson(doc);
 $.writeln(linksJson);
}

Output:

Running the script above will log JSON formatted something like the following example to your console:

{
  "indd-name": "foobar.indd",
  "location": "/path/to/the/document",
  "links":[
    {
      "name": "one.psd",
      "path": "/path/to/the/document/links/one.psd",
      "docId": "5E3AE91C0E2AD0A57A0318E078A125D6",
      "insId": "xmp.iid:0480117407206811AFFD9EEDCD311C32"
    },
    {
      "name": "two.jpg",
      "path": "/path/to/the/document/links/two.jpg",
      "docId": "EDC4CCF902ED087F654B6AB54C57A833",
      "insId": "xmp.iid:FE7F117407206811A61394AAF02B0DD6"
    },
    {
      "name": "three.png",
      "path": "/path/to/the/document/links/three.png",
      "docId": null,
      "insId": null
    }
  ]
}


Sidenote: Modelling your JSON:

You'll have noticed that the JSON output (above) is structured differently to how you were attempting to structure it in your given example. The main difference is that you were using link filenames as property/key names, such as the following example:

Example of a problematic JSON structure

{
  "one.psd": {
    "docId": "5E3AE91C0E2AD0A57A0318E078A125D6",
    "insId": "xmp.iid:0480117407206811AFFD9EEDCD311C32"
  },
  "two.jpg": {
    "docId": "EDC4CCF902ED087F654B6AB54C57A833",
    "insId": "xmp.iid:FE7F117407206811A61394AAF02B0DD6"
  }
  ...
}

Producing JSON like this example isn't ideal because if you were to have two links, both with the same name, you would only ever report one of them. You cannot have two properties/keys that have the same name within an Object.


Edit:

As a response to the OP's comment:

Hi RobC, other than using #include 'json2.js', is there any other way to include external js file in the JSX file?

There are a couple of alternative ways as follows:

  1. You could utilize $.evalFile(). For instance replace #include "json2.js"; with the following two lines:

     var json2 = File($.fileName).path + "/" + "json2.js";
     $.evalFile(json2);
    

    Note: This example assumes json2.js resides in the same folder as your .jsx

  2. Alternatively, if you're wanting to avoid the existence of the additional json2.js file completely. You could add a IIFE (Immediately Invoked Function Expression) at the top of your .jsx file. Then copy and paste the content of the json2.js file into it. For instance:

     (function () {
         // <-- Paste the content of `json2.js` here.
     })();
    

    Note: If code size is a concern then consider minifying the content of json2.js before pasting it into the IIFE.

这篇关于需要在 ExtendScript 中对对象进行 JSON 字符串化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆