Bjorn Backlund
Bjorn Backlund

Reputation: 21

Apps-Script: Element equality?

Since this is always false:

doc.getBody().getParagraphs()[0] == doc.getBody().getParagraphs()[0]

How do you test element equality in Apps-Script?

Upvotes: 2

Views: 662

Answers (4)

bruce
bruce

Reputation: 1408

I'm not entirely sure if you are comparing the contents or the position. Let's assume you can compare the contents with getAsText().

To compare the position, it's fairly easy to create an element index (the path at which an element appears in a document).

  /**
   * create a path in document serial for an element
   * @param {Document.Element} element an element
   * @param {string} [path=''] the path so far
   * @return {string} the path
   */
  function pathInDocument (element,path) {
    path = path || "" ;
    var parent = element.getParent();
    if (parent) {
      path = pathInDocument( parent , Utilities.formatString ( '%04d.%s', parent.getChildIndex(element),path  ));
    }
    return path;
  };

which can be called like this

var path = pathInDocument(element);

and will return something like

0000.0001.0004....etc

If the paths of two elements are the same, they appear in the same position in the document and are therefore the same element.

For an example of using this (in this case to sort bookmarks) see https://ramblings.mcpher.com/google-docs/sorting-bookmarks-in-a-document/

Upvotes: 2

Christopher Terry
Christopher Terry

Reputation: 101

I wrote a recursive solution to avoid string comparison and short-circuit the path walk. Note that you can always convert to loops if you're not happy with the stack dependency of recursion.

function isSameElement(elem1, elem2) {
  if (!elem1 && !elem2) return true;
  if (!elem1 || !elem2) return false;

  var p1=elem1.getParent();
  var p2=elem2.getParent();

  if (!p1 && !p2) {
    return true;
  } else if (!p1 || !p2) {
    return false;
  } else if (p1.getChildIndex(elem1)==p2.getChildIndex(elem2)){
    return isSameElement(p1,p2);
  } else {
    return false;
  }
}

Upvotes: 1

filipeglfw
filipeglfw

Reputation: 779

Eventually I came up with a solution for comparing elements.

first of all let me point that this code works and returns true:

var paragraphs = doc.getBody().getParagraphs();
Logger.log(paragraphs[0] == paragraphs[0]);

that is because you are comparing the same element from an array. The way you did in the question, you had two different arrays of paragraphs.

However there are situations when you can not do that, because you may not be comparing paragraphs, or you don't even know what elements you have.

What I do is create a path to the elements all the way up to the body section of the Document. If the paths are equal, you have the same elements.

function bodyPath(el, path) {
  path = path? path: [];
  var parent = el.getParent();
  var index = parent.getChildIndex(el);
  path.push(index);
  var parentType = parent.getType();
  if (parentType !== DocumentApp.ElementType.BODY_SECTION) {
    path = bodyPath(parent, path);
  } else {
    return path;
  };
  return path;
};

function isSameElement(element1, element2) {
  var path1 = bodyPath(element1);
  var path2 = bodyPath(element2);
  if (path1.length == path2.length) {
    for (var i=0; i<path1.length; i++) {
      if (path1[i] !== path2[i]) {
        return false;
      };
    };
  } else {
    return false;
  };
  return true;
};

This method has proved itself quite fast. Any additions are welcome!

Upvotes: 1

Gerardo
Gerardo

Reputation: 3845

I tried it and its always false, for some reason the method returns different objects.

In this case you are comparing the objects and not the content of the objects which indeed are different. You could get the content of the object with .getText(), then this comparison would return true.

Upvotes: 0

Related Questions