在Extendscript Indesign中对XML元素重新排序

时间:2019-07-03 21:57:12

标签: adobe-indesign extendscript

我想对以下电影列表进行重新排序,以使version==3D的电影应放在version==2D中的电影之前。

输入

<films>
  <film name="Foobar" version="2D"></film>
  <film name="Foobar" version="3D"></film>
  <film name="Foobaz" version="2D"></film>
  <film name="Foobaz" version="3D"></film>
</films>

所需的输出

<films>
  <film name="Foobar" version="3D"></film>
  <film name="Foobar" version="2D"></film>
  <film name="Foobaz" version="3D"></film>
  <film name="Foobaz" version="2D"></film>
</films>

我摆弄了很多,最后得到了以下代码。希望它可以理解。

/***
 Extend Array prototype to have a indeOf function
 ***/
Array.prototype.indexOf = function(item) { 
    var index = 0, length = this.length;  
    for ( ; index < length; index++ ) {
        if ( this[index] == item )  
            return index;  
        }  
    return -1;  
};  


var xmlString = '\
<films>\
    <film name="Foobar" version="2D"></film>\
    <film name="Foobar" version="3D"></film>\
    <film name="Foobaz" version="2D"></film>\
    <film name="Foobaz" version="3D"></film>\
</films>';

var xml = new XML(xmlString);
var sortVersion = ['2D', '3D'];
var uniqueMovies = new Array();


for (var index = 0; index < xml.elements().length(); index++) {
    if (index == 0) continue;

    // Fetch meta data of previous movie
    var prevTitle = xml.elements()[index - 1].@name;
    var prevVersion = xml.elements()[index - 1].@version;
    var prevVersionIdx = sortVersion.indexOf(prevVersion);

    // Fetch meta data of current movie
    var curTitle = xml.elements()[index].@name;
    var curVersion = xml.elements()[index].@version;
    var curVersionIdx = sortVersion.indexOf(curVersion);

    // If both movie title matches verify which movie should be prioritized
    if (prevTitle == curTitle) {
      if (prevVersionIdx < curVersionIdx) { 
          // Movie prio movie before less prio movie
          xml.insertChildBefore(xml.elements()[index - 1], xml.elements()[index]);
          // And delete the next in index
          delete xml.elements()[index + 1];
      }
    }   
}

$.writeln("-----");
$.writeln("");
$.writeln(xml.elements().toString());
return xml

但是,当我运行此脚本时,我得到以下结果,尽管同时满足了两个if条件,并且在index[1]之前添加了index[0]上的元素,但是什么都没有改变。

<films>
  <film name="Foobar" version="2D"/>
  <film name="Foobar" version="3D"/>
  <film name="Foobaz" version="2D"/>
  <film name="Foobaz" version="3D"/>
</films>

有人知道我在做什么错吗?

1 个答案:

答案 0 :(得分:1)

请改用以下方法:

script.jsx

/**
 * Extend Array prototype to have a indexOf function
 */
Array.prototype.indexOf = function(item) {
    var index = 0, length = this.length;
    for ( ; index < length; index++ ) {
        if ( this[index] == item )
            return index;
        }
    return -1;
};

var xmlString = '\
<films>\
  <film name="Foobar" version="2D"></film>\
  <film name="Foobar" version="3D"></film>\
  <film name="Foobaz" version="2D"></film>\
  <film name="Foobaz" version="3D"></film>\
  <film name="Foo" version="3D"></film>\
  <film name="Quux" version="2D"></film>\
  <film name="Quux" version="3D"></film>\
</films>';

var xml = new XML(xmlString);
var sortVersion = ['2D', '3D'];

// 1. Create a temporary XML object with a  matching `films` root element.
var tempXml = new XML('<' + xml.name() + '></' + xml.name() + '>');

for (var index = 0, max = xml.elements().length(); index < max; index++) {

  // Fetch meta data of previous movie
  var prevTitle = String(xml.elements()[index - 1].@name);
  var prevVersion = xml.elements()[index - 1].@version;
  var prevVersionIdx = sortVersion.indexOf(prevVersion);

  // Fetch meta data of current movie
  var curTitle = String(xml.elements()[index].@name);
  var curVersion = xml.elements()[index].@version;
  var curVersionIdx = sortVersion.indexOf(curVersion);

  // 2. Insert each XML element node from the original XML Object into
  // the temporary XML Object and position (i.e. sort) as neccessary.
  if (prevTitle === curTitle && prevVersion < curVersion) {
    tempXml.insertChildBefore(tempXml.elements()[index -1], xml.elements()[index])
  } else {
    // There's nothing to change (i.e. sort) so insert it as-is .
    tempXml.insertChildBefore(tempXml.elements()[index], xml.elements()[index])
  }
}

// 3. Overwrite original XML object's children with temporary (sorted) XML objects children.
xml.setChildren(tempXml.children());

// 4. Delete temporary XML object.
tempXml = undefined;


// Testing...
$.writeln(xml)
$.writeln('-----------------')
$.writeln(xml.elements().length())
$.writeln('-----------------')

说明:

上面的要点不是尝试操作(即排序)原始XML对象,而是执行以下操作:

  1. 创建另一个仅包含<films>根元素的XML对象。此XML对象将是临时的。

  2. for循环的每一圈中,我们;

    • 将每个XML元素节点的克隆从原始XML对象插入到临时XML对象中。
    • 根据需要对每个XML元素节点进行定位(即排序)。
  3. 用临时/排序后的XML对象中的子元素节点覆盖原始XML对象的子元素节点。

  4. 最后,我们删除了不再需要的临时XML对象(即,将其设置为undefined)。


结果

上面的示例要点包括以下源XML:

<films>
  <film name="Foobar" version="2D"></film>
  <film name="Foobar" version="3D"></film>
  <film name="Foobaz" version="2D"></film>
  <film name="Foobaz" version="3D"></film>
  <film name="Foo" version="3D"></film>
  <film name="Quux" version="2D"></film>
  <film name="Quux" version="3D"></film>
</films>

将转换为以下内容:

<films>
  <film name="Foobar" version="3D"/>
  <film name="Foobar" version="2D"/>
  <film name="Foobaz" version="3D"/>
  <film name="Foobaz" version="2D"/>
  <film name="Foo" version="3D"/>
  <film name="Quux" version="3D"/>
  <film name="Quux" version="2D"/>
</films>

注意:对于比您的问题中提供的示例更复杂的XML结构和转换要求,我考虑改用XSLT。根据您当前的要求,像this one这样的模板将达到您想要的结果。