在 Extendscript Indesign 中重新排序 XML 个元素
Reorder XML Elements in Extendscript Indesign
我想重新排列以下电影列表,使 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]
上的元素添加在 [=18= 之前].
<films>
<film name="Foobar" version="2D"/>
<film name="Foobar" version="3D"/>
<film name="Foobaz" version="2D"/>
<film name="Foobaz" version="3D"/>
</films>
有人知道我做错了什么吗?
请考虑以下方法:
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 对象,而是执行以下操作:
创建另一个仅包含 <films>
根元素的 XML 对象。此 XML 对象将是临时的。
在 for
循环的每一轮中,我们;
- 将每个 XML 元素节点的克隆从原始 XML 对象插入临时 XML 对象。
- 根据需要定位(即排序)每个 XML 元素节点。
用temporary/sortedXML对象的子元素节点覆盖原来的XML对象子元素节点。
最后我们删除了临时 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 instead. Given your current requirement a template like this one 来实现您的期望的结果。
我想重新排列以下电影列表,使 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]
上的元素添加在 [=18= 之前].
<films>
<film name="Foobar" version="2D"/>
<film name="Foobar" version="3D"/>
<film name="Foobaz" version="2D"/>
<film name="Foobaz" version="3D"/>
</films>
有人知道我做错了什么吗?
请考虑以下方法:
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 对象,而是执行以下操作:
创建另一个仅包含
<films>
根元素的 XML 对象。此 XML 对象将是临时的。在
for
循环的每一轮中,我们;- 将每个 XML 元素节点的克隆从原始 XML 对象插入临时 XML 对象。
- 根据需要定位(即排序)每个 XML 元素节点。
用temporary/sortedXML对象的子元素节点覆盖原来的XML对象子元素节点。
最后我们删除了临时 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 instead. Given your current requirement a template like this one 来实现您的期望的结果。