【问题标题】:Need to JSON stringify an object in ExtendScript需要对 ExtendScript 中的对象进行 JSON 字符串化
【发布时间】:2019-10-15 22:13:32
【问题描述】:

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

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

can't execute script in target engine.

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

ExtendScript 中的JSON.stringify 等价于什么,或者是否有任何其他可能以正确的内容显示linksInfObj 而不是[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);

}

【问题讨论】:

  • 如果您使用的是 vscode 调试器,根据我的经验,该错误意味着语法错误,或者找不到包含文件。

标签: javascript adobe adobe-indesign extendscript


【解决方案1】:

ExtendScript 不包含带有相关解析方法的 JSON 对象,即JSON.parse()JSON.stringify()。它也不提供任何其他用于解析 JSON 的内置功能。


解决方案:

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

您需要做什么:

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

    注意如果您愿意,您可以从同一个 Github 存储库中复制并粘贴 raw version of 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;

/**
 * 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);
}

输出:

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

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

旁注:为您的 JSON 建模:

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

有问题的 JSON 结构示例

{
  "one.psd": {
    "docId": "5E3AE91C0E2AD0A57A0318E078A125D6",
    "insId": "xmp.iid:0480117407206811AFFD9EEDCD311C32"
  },
  "two.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 文件的存在。您可以在.jsx 文件的顶部添加一个IIFE(立即调用函数表达式)。然后将json2.js 文件的内容复制并粘贴到其中。例如:

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

    注意:如果代码大小是一个问题,那么在将 minifying 的内容粘贴到 IIFE 之前,请考虑 json2.js 的内容。

【讨论】:

  • FWIW,json2.js 在 ExtendScript 和明显的枚举转换方面存在一些问题。人们可能更喜欢 Marc Autret 自己的 IDExtenso 框架实现:github.com/indiscripts/IdExtenso
  • 有趣,但不幸的是,IDExtenso 仅适用于 ExtendScript ToolKit (ESTK),不适用于 Visual Studio Code。
  • JSON-js 效果很好——直到有人尝试在 Visual Studio Code 的 ExtendScript CEP 面板中使用它。在 VSCode 中的独立 .jsx 中对其进行测试,JSON.stringify() 和 JSON.parse() 对对象和对象数组进行编码和解码。但是如果你幸运的话,通过 evalScript() 发送完全相同的数据,你得到的只是“EvalScript 错误”。实在是太糟糕了,不过我又来join()和split()了。
  • 另外,VSCode 中 .jsx 文件的 include 语句为://@include "./JSON-js/json2.js"
  • 您可以想象,EvalScript 可能不起作用,因为任何类型的包含都依赖于实际的文件位置,而 EvalScript 中的脚本没有物理位置。我在使用 evalJSXFile 时遇到了类似的问题,显然它也不起作用,因为 ExtendScript 不会获取包含的脚本。如果您必须在脚本中使用 JSON,您可以通过将整个 json2.js 嵌入到脚本中来解决。
【解决方案2】:

我将JavaScript Minifier 申请到JSON-js

然后将结果放到我的脚本中。

【讨论】:

    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    相关资源
    最近更新 更多