function parseTemplate(id, data) {
  var node = null;
  var template = document.getElementById(id);
  var tpl = template.content.firstElementChild.outerHTML;

  var getDataByPath = function getDataByPath(obj, path) {
    var parts = path.split('.');
    var cur = obj;
    for (var k = 0; k < parts.length; k++) {
      var part = parts[k];
      if (cur[part] === undefined) {
        return null;
      } else if (cur[part] === null || cur[part].length === 0) {
        return '';
      } else {
        cur = cur[part];
      }
    }
    return cur;
  };

  var parseRow = function parseRow(originalTpl, rowData) {
    var newTpl = originalTpl;
    newTpl = newTpl.replace(/{{ ([a-zA-Z0-9\-._]*) }}/g, function (match, capture) {
      var res = getDataByPath(rowData, capture);
      return res === null ? match : res;
    });

    var node = htmlToNode(newTpl);
    if (node.tagName === 'TABLE') {
      node = node.rows[0];
    }

    if (template._handlers !== undefined) {
      for (var handlerName in template._handlers) {
        var el = node.querySelector('[handler="' + handlerName + '"]');
        template._handlers[handlerName](el);
      }
    }

    return node;
  };

  if (Array.isArray(data)) {
    node = document.createDocumentFragment();
    data.forEach(function (row) {
      node.appendChild(parseRow(tpl, row));
    });
  } else {
    node = parseRow(tpl, data);
  }

  return node;
}
Parses <template> contents by ID and replaces all {{ var }} inside
Second param should be an object of var keys => var values
If second params is an Array of Objects, returns DocumentFragment
Else - Node

@param {String} id
@param {Object|Array} data
@returns {Node|DocumentFragment} node