如何通过将设计中的XML元素添加到父标签中来对它们进行分组 [英] How to group XML elements in in-design by adding them to a parent tag

查看:108
本文介绍了如何通过将设计中的XML元素添加到父标签中来对它们进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有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:


  1. 创建新的InDesign文档。

  2. 选择从菜单栏中查看> 结构> 显示结构以显示 XML结构 面板。

  3. XML结构 面板中,选择默认的 Root XML

  4. XML Structure 面板中,从下拉菜单中选择 Import XMl

  5. 找到上述 sample.xml 文件并打开它。

  6. 最后保存文档

  1. Create a new InDesign document.
  2. Select View > Structure > Show Structure from the Menu Bar to reveal the XML Structure panel.
  3. In the XML Structure panel select the default Root XML element.
  4. In the XML Structure panel choose Import XMl from the dropdown menu.
  5. Locate the aforementioned sample.xml file and open it.
  6. 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 (上面)将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' });

这次我们基本上是:


  1. 获取对 EL 元素的引用(因为这是包含我们要移动的子元素的父元素)并将其分配给变量名为 parentElement

  1. 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 <时定义的位置范围/ code>函数。

这篇关于如何通过将设计中的XML元素添加到父标签中来对它们进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆