需要 JSON 将 ExtendScript 中的对象字符串化

Need to JSON stringify an object in ExtendScript

我正在使用 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);

}

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

的内置功能

解决方案:

考虑使用 Douglas Crockford 创建的 polyfill to provide JSON functionality such as JSON-js

您需要做的事情:

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

    注意 您只需从同一个 Github 存储库复制并粘贴 raw version of json2.js 即可创建 json2.js 如果愿意,请手动归档。

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

     #include "json2.js";
    

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

    如果您决定将文件保存在与 .jsx 文件.

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


示例:

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

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 输出(上图)的结构与您在给定示例中尝试构建它的方式不同。主要区别在于您使用 link 文件名作为 property/key 名称,例如以下示例:

有问题的示例 JSON 结构

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

像这个例子一样生成 JSON 并不理想,因为如果您有两个 link,并且都具有相同的名称,您将只会报告其中一个。一个对象中不能有两个同名的 properties/keys。


编辑:

作为对 OP 评论的回应:

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

有以下几种替代方法:

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

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

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

    位于同一文件夹中
  2. 或者,如果您想完全避免附加 json2.js 文件的存在。您可以在其中添加一个 IIFE (Immediately Invoked Function Expression) at the top of your .jsx file. Then copy and paste the content of the json2.js 文件。例如:

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

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

我申请了JavaScript Minifier to JSON-js

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