如何通过将设计中的XML元素添加到父标签中来对它们进行分组 [英] How to group XML elements in in-design by adding them to a parent tag
问题描述
我有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:
- 创建新的InDesign文档。
- 选择
从菜单栏中查看
>结构
>显示结构
以显示 XML结构 面板。 - 在 XML结构 面板中,选择默认的
Root
XML - 在 XML Structure 面板中,从下拉菜单中选择
Import XMl
。 - 找到上述
sample.xml
文件并打开它。 - 最后保存文档
- Create a new InDesign document.
- Select
View
>Structure
>Show Structure
from the Menu Bar to reveal the XML Structure panel. - In the XML Structure panel select the default
Root
XML element. - In the XML Structure panel choose
Import XMl
from the dropdown menu. - Locate the aforementioned
sample.xml
file and open it. - Finally save the document
注意:在整个答案中,我们将需要还原 .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 $中提供的代码c $ c>(上面)将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 namedparentElement
.
调用 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 theEL
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' }
- Anoptions
object which includes a key/property namedtagName
with a value ofsection
.
注意:这次我们通过了可选的选项
对象,该对象为新创建的父元素指定名称,即 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 <时定义的位置范围/ code>函数。
这篇关于如何通过将设计中的XML元素添加到父标签中来对它们进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!