我有XML元素链接到文档的根元素,并且应该对某些元素进行分组,然后再链接到设计文档,所以我想知道如何创建虚拟组并将元素添加到一个父标记,该子标记将依次成为InDesign脚本中父标记的子标记
I have XML elements linked to the root element of the document and there are some elements that should be grouped and then linked to the design document, So I would like to know how I can create a virtual group and add the elements to a parent tag that will, in turn, be the child of the parent in InDesign scripting
现有的
-EL1 -EL2 -EL3 -EL4 -EL5预期:
-EL1 -EL --EL2 --EL3 --EL4 -EL5其中 EL 是父元素,而 EL2,EL3,EL4 是子元素。
Where EL is the parent and EL2,EL3,EL4 are the child elements.
推荐答案设置演示.indd
为此回答提供一些背景信息,并为了便于说明和演示,首先将以下XML文档导入到新的inDesign文档中:
Setup a demo .indd
To provide some context for this answer, and to aid explanation and demonstration, firstly import the following XML document into a new inDesign document:
sample.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Root> <EL1>Para 1</EL1> <EL2>Para 2</EL2> <EL3>Para 3</EL3> <EL4>Para 4</EL4> <EL5>Para 5</EL5> <EL6>Para 6</EL6> <EL7>Para 7</EL7> <EL8>Para 8</EL8> <EL9>Para 9</EL9> </Root>要将 sample.xml 导入到新文档请按照以下步骤操作:
To import the sample.xml into a new document follow these steps:
注意:在整个答案中,我们将需要还原 .indd 文件返回到此初始状态-因此请确保将其保存。
Note: Throughout this answer we'll need to revert the .indd file back to this starting state - so please ensure you save it.
文档XML树的结构现在应如下所示:
The documents XML tree should now be structured as follows:
初始XML树结构:
Root ├── EL1 ├── EL2 ├── EL3 ├── EL4 ├── EL5 ├── EL6 ├── EL7 ├── EL8 └── EL9正如您所看到的,它与您在问题中所描述的非常相似,但是还有更多元素,即; EL6 , EL7 , EL8 , EL9 。
As you can see it's very similar to what you described in your question, however there's just a few more elements, namely; EL6, EL7,EL8, EL9.
example-a.jsx
#target indesign // 1. Obtain a reference to the active document. var doc = app.activeDocument; // 2. Obtain a reference to the root element var root = doc.xmlElements.item(0); // 3. Create a new tag var newParentTag = doc.xmlTags.add("EL"); // 4. Create a new element node var parentNode = root.xmlElements.add(newParentTag.name); // 5. Change the position of the newly created element node parentNode.move(LocationOptions.before, root.xmlElements.item(1)); // 6. Move elements to be children of the newly created parent element. root.xmlElements.item(4).move(LocationOptions.atBeginning, root.xmlElements.item(1)); root.xmlElements.item(3).move(LocationOptions.atBeginning, root.xmlElements.item(1)); root.xmlElements.item(2).move(LocationOptions.atBeginning, root.xmlElements.item(1));如果我们运行 example-a.jsx (上面)将XML树重新构造为以下内容:
If we run the code provided in example-a.jsx (above) it will restructure the XML tree to the following:
XML树结构在以下位置:
Root ├── EL1 ├── EL │ ├── EL2 │ ├── EL3 │ └── EL4 ├── EL5 ├── EL6 ├── EL7 ├── EL8 └── EL9注意:在继续进行解决方案B (如下)之前,请先将Design文档中的演示还原为原始状态。从菜单栏中选择文件> 还原。
Note: Before proceeding to Solution B (below) please revert the demo inDesign document to it's original state. Select File > Revert from the Menu Bar.
如果您打算经常重组XML树,即您打算移动各种子元素到一个新的父元素,那么我会考虑利用一个辅助函数,例如下面所示的 childElementsToNewParent 函数。通过这样做,您可以提供一个更简单的界面来执行此任务。
If you intend to restructure the XML tree often, i.e. you intent to move various child elements to a new parent element often, then I would consider utilizing a helper function such as the childElementsToNewParent function shown below. By doing this you can provide a simpler interface for performing this task.
example-b.jsx
#target indesign $.level=0; //------------------------------------------------------------------------------ // Usage //------------------------------------------------------------------------------ // 1. Obtain a reference to the active document. var doc = app.activeDocument; // 2. Obtain a reference to the root element var rootElement = doc.xmlElements.item(0); // 3. Restructure the XML tree. childElementsToNewParent(doc, rootElement, 2, 4); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /** * Moves child element(s) at a given position within a given parent element to * a new parent element. * * @param {Object} doc - A document reference for changing its XML structure. * @param {Object} parent - The parent XMlElement whose children need to move. * @param {Number} from - The position of the first child element to move. * @param {Number} to - The position of the last child element to move. * @param {Object} options - The configuration options. * @param {String} [options.tagName=undefined] - A custom name for the newly * created parent XML element. */ function childElementsToNewParent(doc, parent, from, to, options) { // Default options var opts = { tagName: undefined } // Override the default opts with any user defined options. opts = assign(options, opts); var xPath = '*[position() >= ' + from + ' and position() <= ' + to + ']'; var childrenToMove = parent.evaluateXPathExpression(xPath); // XMLElements matched by the `evaluateXPathExpression` method are returned // in any order. We sort each element object in the array by it positional // index to ensure that when we move them to a new parent element their // positional order is preserved as-is. childrenToMove = sortArrayOfObjects(childrenToMove, 'index'); var firstChildToMove = childrenToMove[0]; var firstChildToMoveIndex = firstChildToMove.index; var xmlTagName = opts.tagName ? opts.tagName : firstChildToMove.markupTag.name.substring(0, 2); createXmlTag(doc, xmlTagName); // Move the newly created parent XMLElement to // before the first child element to be moved. parent.xmlElements.add(xmlTagName).move( LocationOptions.before, parent.xmlElements.item(firstChildToMoveIndex) ); // Move each the matched child XMLElement(s) into their new parent XMLElement. for (var i = 0, max = childrenToMove.length; i < max; i++) { childrenToMove[i].move( LocationOptions.atEnd, parent.xmlElements.item(firstChildToMoveIndex) ); } } /** * Enumerates own properties of a 'source' object and copies them to a 'target' * object. Properties in the 'target' object are overwritten by properties in * the 'source' object if they have the same key. * * @param {Object} source - The object containing the properties to apply. * @param {Object} target - The object to apply the source object properties to. * @returns {Object} - The target object. */ function assign(source, target) { if (typeof source === 'object') { for (key in source) { if (source.hasOwnProperty(key) && target.hasOwnProperty(key)) { target[key] = source[key]; } } } return target; } /** * Sorts array of objects by value of property name in ascending order. * * @param {Array} arr - The array of objects to sort. * @param {String} prop - The name of the object property to sort by. * @returns {Array} - Array of objects sorted by value of property name. */ function sortArrayOfObjects(arr, prop) { return arr.sort(function sortByPropertyValue(a, b) { if (a[prop] < b[prop]) { return -1; } if (a[prop] > b[prop]) { return 1; } return 0; }); } /** * Creates a new XML tag if the given name does not already exist. * * @param {String} tagName - The name of the XML tag. * @param {Object} doc - A reference to the document to add the XMl tag to. */ function createXmlTag(doc, tagName) { var hasTag = inArray(tagName, doc.xmlTags.everyItem().name); if (! hasTag) { doc.xmlTags.add(tagName); } } /** * Determines whether an array includes a certain value among its elements. * * @param {String} valueToFind - The value to search for. * @param {Array} arrayToSearch - The array to search in. * @returns {Boolean} true if valueToFind is found within the array. */ function inArray(valueToFind, arrayToSearch) { for (var i = 0, max = arrayToSearch.length; i < max; i++) { if (arrayToSearch[i] === valueToFind) { return true; } } return false; }如果我们运行 example-a.jsx (如上),它将把XML树重构为与中的之后的XML树结构 部分所示的结果结构相同的结构。解决方案A 。
If we run the code provided in example-a.jsx (above) it will restructure the XML tree to the same resultant structure as shown in the "XML tree structure after" section of "Solution A".
注意:不要还原 indd 文档-保留原样,以使以下用法示例与之相关。
Note: Don't revert the indd document just yet - leave it as-is for the following usage example to be relevant.
让我们现在想从先前显示的之后的XML树结构重构树变为以下状态:
Let's say we now want to restructure the tree from the previously shown "XML tree structure after" state to the following state:
下一个所需的XML树结构:
Root ├── EL1 ├── EL │ ├── EL2 │ └── section │ ├── EL3 │ └── EL4 ├── EL5 ├── EL6 ├── EL7 ├── EL8 └── EL9要实现此结构,我们需要替换以下行:
To achieve this structure we need to replace the the following line:
// 3. Restructure the XML tree. childElementsToNewParent(doc, rootElement, 2, 4);...当前在 example-b.jsx中定义,即调用 childElementsToNewParent 函数的行,而改为以下两行:
...that is currently defined in example-b.jsx, i.e. the line that invokes the childElementsToNewParent function, with the following two lines instead:
var parentElement = rootElement.xmlElements.item(1); childElementsToNewParent(doc, parentElement, 2, 3, { tagName: 'section' });这次我们基本上是:
获取对 EL 元素的引用(因为这是包含我们要移动的子元素的父元素)并将其分配给变量名为 parentElement 。
Obtaining a reference to the EL element (as that's the parent element containing the child elements we want to move) and assigning it to a variable named parentElement.
调用 childElementsToNewParent 具有以下参数的函数:
Invoking the childElementsToNewParent function with the following arguments:
- doc -对文档的引用我们要更改其XML结构。
- parentElement -该变量的值是对 EL的引用元素。
- 2 -我们要移动的子元素的第一个位置。
- 3 -我们要移动的子元素的最后位置。
- {tagName:'section'} -一个 options 对象,其中包含名为 tagName 的值为部分。
- doc - A reference to the document that we want to change its XML structure.
- parentElement - The variable whose value is a reference to the EL element.
- 2 - The first position of the child element that we want to move.
- 3 - The last position of the child element that we want to move.
- { tagName: 'section' } - An options object which includes a key/property named tagName with a value of section.
注意:这次我们通过了可选的选项对象,该对象为新创建的父元素指定名称,即 section 。调用 childElementsToNewParent 函数时,没有在选项$中提供 tagName 的值c $ c>对象,我们使用要移动的第一个子元素的前两个字符来推断新父元素的名称。根据您的评论:
Note: This time we passed an optional options object that specified the name for the newly created parent element, namely section. When invoking the childElementsToNewParent function without providing a value for tagName in the the options object we infer the name for the new parent element by using the first two characters of the first child element to be move. As per your comment:
...父名称是所选元素的前两个字符
... the parent name is the first two characters of the elements selected
附加说明
您会注意到,在最后一个示例中,我们获得了通过使用以下表示法对 EL 元素的引用(即对包含我们要移动的子元素的父元素的引用);
You'll have noticed in that last example we obtained a reference to the EL element, (i.e. the reference to the parent element containing the child elements that we wanted to move), by utilizing the following notation;
var parentElement = rootElement.xmlElements.item(1);...当想要获得对深层嵌套元素的引用时,它会变得很长。您最终将执行以下操作:
... which can get get rather long when wanting to obtain a reference to a deeply nested element. You'll end up doing something like this:
var parentElement = rootElement.xmlElements.item(1).xmlElements.item(3).xmlElements.item(1) ....I倾向于使用 evaluateXPathExpression 方法,因为它允许我们使用xpath 表达式。例如,要获取对 EL 元素的引用,我们可以改为
I prefer utilizing the evaluateXPathExpression method instead as this allows us to match the element using an xpath expression. For example to obtain the reference to the EL element we could do this instead
var parentElement = rootElement.evaluateXPathExpression('EL')[0];如您所见,我们还利用了 evaluateXPathExpression $ childElementsToNewParent 函数主体中的c $ c>方法来获取对我们要移动的子元素的引用:
As you can see, we're also utilizing the evaluateXPathExpression method in the body of the childElementsToNewParent function to obtain a reference to the child elements that we want to move:
var xPath = '*[position() >= ' + from + ' and position() <= ' + to + ']'; var childrenToMove = parent.evaluateXPathExpression(xPath);
此表达式使用XPath的 position() 函数以查找给定位置范围内的子元素。实际上,这是您将 from 和到参数传递给 childElementsToNewParent 函数。
更多推荐
如何通过将设计中的XML元素添加到父标签中来对它们进行分组
发布评论