UNPKG

simple-xpath-position

Version:

Create and evaluate simple XPath position expressions.

167 lines (141 loc) 15.9 kB
'use strict'; exports.__esModule = true; exports.fromNode = fromNode; exports.toNode = toNode; var _getDocument = require('get-document'); var _getDocument2 = _interopRequireDefault(_getDocument); var _domException = require('./dom-exception'); var _domException2 = _interopRequireDefault(_domException); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } // https://developer.mozilla.org/en-US/docs/XPathResult var FIRST_ORDERED_NODE_TYPE = 9; // Default namespace for XHTML documents var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; /** * Compute an XPath expression for the given node. * * If the optional parameter `root` is supplied, the computed XPath expression * will be relative to it. Otherwise, the root element is the root of the * document to which `node` belongs. * * @param {Node} node The node for which to compute an XPath expression. * @param {Node} [root] The root context for the XPath expression. * @returns {string} */ function fromNode(node) { var root = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; if (node === undefined) { throw new Error('missing required parameter "node"'); } root = root || (0, _getDocument2['default'])(node); var path = '/'; while (node !== root) { if (!node) { var message = 'The supplied node is not contained by the root node.'; var name = 'InvalidNodeTypeError'; throw new _domException2['default'](message, name); } path = '/' + nodeName(node) + '[' + nodePosition(node) + ']' + path; node = node.parentNode; } return path.replace(/\/$/, ''); } /** * Find a node using an XPath relative to the given root node. * * The XPath expressions are evaluated relative to the Node argument `root`. * * If the optional parameter `resolver` is supplied, it will be used to resolve * any namespaces within the XPath. * * @param {string} path An XPath String to evaluate. * @param {Node} root The root context for the XPath expression. * @returns {Node|null} The first matching Node or null if none is found. */ function toNode(path, root) { var resolver = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; if (path === undefined) { throw new Error('missing required parameter "path"'); } if (root === undefined) { throw new Error('missing required parameter "root"'); } // Make the path relative to the root, if not the document. var document = (0, _getDocument2['default'])(root); if (root !== document) path = path.replace(/^\//, './'); // Make a default resolver. var documentElement = document.documentElement; if (resolver === null && documentElement.lookupNamespaceURI) { (function () { var defaultNS = documentElement.lookupNamespaceURI(null) || HTML_NAMESPACE; resolver = function resolver(prefix) { var ns = { '_default_': defaultNS }; return ns[prefix] || documentElement.lookupNamespaceURI(prefix); }; })(); } return resolve(path, root, resolver); } // Get the XPath node name. function nodeName(node) { switch (node.nodeName) { case '#text': return 'text()'; case '#comment': return 'comment()'; case '#cdata-section': return 'cdata-section()'; default: return node.nodeName.toLowerCase(); } } // Get the ordinal position of this node among its siblings of the same name. function nodePosition(node) { var name = node.nodeName; var position = 1; while (node = node.previousSibling) { if (node.nodeName === name) position += 1; } return position; } // Find a single node with XPath `path` function resolve(path, root, resolver) { try { // Add a default value to each path part lacking a prefix. var nspath = path.replace(/\/(?!\.)([^\/:\(]+)(?=\/|$)/g, '/_default_:$1'); return platformResolve(nspath, root, resolver); } catch (err) { return fallbackResolve(path, root); } } // Find a single node with XPath `path` using the simple, built-in evaluator. function fallbackResolve(path, root) { var steps = path.split("/"); var node = root; while (node) { var step = steps.shift(); if (step === undefined) break; if (step === '.') continue; var _step$split = step.split(/[\[\]]/); var name = _step$split[0]; var position = _step$split[1]; name = name.replace('_default_:', ''); position = position ? parseInt(position) : 1; node = findChild(node, name, position); } return node; } // Find a single node with XPath `path` using `document.evaluate`. function platformResolve(path, root, resolver) { var document = (0, _getDocument2['default'])(root); var r = document.evaluate(path, root, resolver, FIRST_ORDERED_NODE_TYPE, null); return r.singleNodeValue; } // Find the child of the given node by name and ordinal position. function findChild(node, name, position) { for (node = node.firstChild; node; node = node.nextSibling) { if (nodeName(node) === name && --position === 0) break; } return node; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy94cGF0aC5qcyJdLCJuYW1lcyI6WyJmcm9tTm9kZSIsInRvTm9kZSIsIkZJUlNUX09SREVSRURfTk9ERV9UWVBFIiwiSFRNTF9OQU1FU1BBQ0UiLCJub2RlIiwicm9vdCIsInVuZGVmaW5lZCIsIkVycm9yIiwicGF0aCIsIm1lc3NhZ2UiLCJuYW1lIiwibm9kZU5hbWUiLCJub2RlUG9zaXRpb24iLCJwYXJlbnROb2RlIiwicmVwbGFjZSIsInJlc29sdmVyIiwiZG9jdW1lbnQiLCJkb2N1bWVudEVsZW1lbnQiLCJsb29rdXBOYW1lc3BhY2VVUkkiLCJkZWZhdWx0TlMiLCJwcmVmaXgiLCJucyIsInJlc29sdmUiLCJ0b0xvd2VyQ2FzZSIsInBvc2l0aW9uIiwicHJldmlvdXNTaWJsaW5nIiwibnNwYXRoIiwicGxhdGZvcm1SZXNvbHZlIiwiZXJyIiwiZmFsbGJhY2tSZXNvbHZlIiwic3RlcHMiLCJzcGxpdCIsInN0ZXAiLCJzaGlmdCIsInBhcnNlSW50IiwiZmluZENoaWxkIiwiciIsImV2YWx1YXRlIiwic2luZ2xlTm9kZVZhbHVlIiwiZmlyc3RDaGlsZCIsIm5leHRTaWJsaW5nIl0sIm1hcHBpbmdzIjoiOzs7UUFzQmdCQSxRLEdBQUFBLFE7UUFpQ0FDLE0sR0FBQUEsTTs7QUF2RGhCOzs7O0FBRUE7Ozs7OztBQUVBO0FBQ0EsSUFBTUMsMEJBQTBCLENBQWhDOztBQUVBO0FBQ0EsSUFBTUMsaUJBQWlCLDhCQUF2Qjs7QUFHQTs7Ozs7Ozs7Ozs7QUFXTyxTQUFTSCxRQUFULENBQWtCSSxJQUFsQixFQUFxQztBQUFBLE1BQWJDLElBQWEseURBQU4sSUFBTTs7QUFDMUMsTUFBSUQsU0FBU0UsU0FBYixFQUF3QjtBQUN0QixVQUFNLElBQUlDLEtBQUosQ0FBVSxtQ0FBVixDQUFOO0FBQ0Q7O0FBRURGLFNBQU9BLFFBQVEsOEJBQVlELElBQVosQ0FBZjs7QUFFQSxNQUFJSSxPQUFPLEdBQVg7QUFDQSxTQUFPSixTQUFTQyxJQUFoQixFQUFzQjtBQUNw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bnQgZnJvbSAnZ2V0LWRvY3VtZW50J1xuXG5pbXBvcnQgRE9NRXhjZXB0aW9uIGZyb20gJy4vZG9tLWV4Y2VwdGlvbidcblxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9YUGF0aFJlc3VsdFxuY29uc3QgRklSU1RfT1JERVJFRF9OT0RFX1RZUEUgPSA5XG5cbi8vIERlZmF1bHQgbmFtZXNwYWNlIGZvciBYSFRNTCBkb2N1bWVudHNcbmNvbnN0IEhUTUxfTkFNRVNQQUNFID0gJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnXG5cblxuLyoqXG4gKiBDb21wdXRlIGFuIFhQYXRoIGV4cHJlc3Npb24gZm9yIHRoZSBnaXZlbiBub2RlLlxuICpcbiAqIElmIHRoZSBvcHRpb25hbCBwYXJhbWV0ZXIgYHJvb3RgIGlzIHN1cHBsaWVkLCB0aGUgY29tcHV0ZWQgWFBhdGggZXhwcmVzc2lvblxuICogd2lsbCBiZSByZWxhdGl2ZSB0byBpdC4gT3RoZXJ3aXNlLCB0aGUgcm9vdCBlbGVtZW50IGlzIHRoZSByb290IG9mIHRoZVxuICogZG9jdW1lbnQgdG8gd2hpY2ggYG5vZGVgIGJlbG9uZ3MuXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIFRoZSBub2RlIGZvciB3aGljaCB0byBjb21wdXRlIGFuIFhQYXRoIGV4cHJlc3Npb24uXG4gKiBAcGFyYW0ge05vZGV9IFtyb290XSBUaGUgcm9vdCBjb250ZXh0IGZvciB0aGUgWFBhdGggZXhwcmVzc2lvbi5cbiAqIEByZXR1cm5zIHtzdHJpbmd9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tTm9kZShub2RlLCByb290ID0gbnVsbCkge1xuICBpZiAobm9kZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHBhcmFtZXRlciBcIm5vZGVcIicpXG4gIH1cblxuICByb290ID0gcm9vdCB8fCBnZXREb2N1bWVudChub2RlKVxuXG4gIGxldCBwYXRoID0gJy8nXG4gIHdoaWxlIChub2RlICE9PSByb290KSB7XG4gICAgaWYgKCFub2RlKSB7XG4gICAgICBsZXQgbWVzc2FnZSA9ICdUaGUgc3VwcGxpZWQgbm9kZSBpcyBub3QgY29udGFpbmVkIGJ5IHRoZSByb290IG5vZGUuJ1xuICAgICAgbGV0IG5hbWUgPSAnSW52YWxpZE5vZGVUeXBlRXJyb3InXG4gICAgICB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKG1lc3NhZ2UsIG5hbWUpXG4gICAgfVxuICAgIHBhdGggPSBgLyR7bm9kZU5hbWUobm9kZSl9WyR7bm9kZVBvc2l0aW9uKG5vZGUpfV0ke3BhdGh9YFxuICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGVcbiAgfVxuICByZXR1cm4gcGF0aC5yZXBsYWNlKC9cXC8kLywgJycpXG59XG5cblxuLyoqXG4gKiBGaW5kIGEgbm9kZSB1c2luZyBhbiBYUGF0aCByZWxhdGl2ZSB0byB0aGUgZ2l2ZW4gcm9vdCBub2RlLlxuICpcbiAqIFRoZSBYUGF0aCBleHByZXNzaW9ucyBhcmUgZXZhbHVhdGVkIHJlbGF0aXZlIHRvIHRoZSBOb2RlIGFyZ3VtZW50IGByb290YC5cbiAqXG4gKiBJZiB0aGUgb3B0aW9uYWwgcGFyYW1ldGVyIGByZXNvbHZlcmAgaXMgc3VwcGxpZWQsIGl0IHdpbGwgYmUgdXNlZCB0byByZXNvbHZlXG4gKiBhbnkgbmFtZXNwYWNlcyB3aXRoaW4gdGhlIFhQYXRoLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIEFuIFhQYXRoIFN0cmluZyB0byBldmFsdWF0ZS5cbiAqIEBwYXJhbSB7Tm9kZX0gcm9vdCBUaGUgcm9vdCBjb250ZXh0IGZvciB0aGUgWFBhdGggZXhwcmVzc2lvbi5cbiAqIEByZXR1cm5zIHtOb2RlfG51bGx9IFRoZSBmaXJzdCBtYXRjaGluZyBOb2RlIG9yIG51bGwgaWYgbm9uZSBpcyBmb3VuZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvTm9kZShwYXRoLCByb290LCByZXNvbHZlciA9IG51bGwpIHtcbiAgaWYgKHBhdGggPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBwYXJhbWV0ZXIgXCJwYXRoXCInKVxuICB9XG4gIGlmIChyb290ID09PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW1ldGVyIFwicm9vdFwiJylcbiAgfVxuXG4gIC8vIE1ha2UgdGhlIHBhdGggcmVsYXRpdmUgdG8gdGhlIHJvb3QsIGlmIG5vdCB0aGUgZG9jdW1lbnQuXG4gIGxldCBkb2N1bWVudCA9IGdldERvY3VtZW50KHJvb3QpXG4gIGlmIChyb290ICE9PSBkb2N1bWVudCkgcGF0aCA9IHBhdGgucmVwbGFjZSgvXlxcLy8sICcuLycpXG5cbiAgLy8gTWFrZSBhIGRlZmF1bHQgcmVzb2x2ZXIuXG4gIGxldCBkb2N1bWVudEVsZW1lbnQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRcbiAgaWYgKHJlc29sdmVyID09PSBudWxsICYmIGRvY3VtZW50RWxlbWVudC5sb29rdXBOYW1lc3BhY2VVUkkpIHtcbiAgICBsZXQgZGVmYXVsdE5TID0gZG9jdW1lbnRFbGVtZW50Lmxvb2t1cE5hbWVzcGFjZVVSSShudWxsKSB8fCBIVE1MX05BTUVTUEFDRVxuICAgIHJlc29sdmVyID0gKHByZWZpeCkgPT4ge1xuICAgICAgbGV0IG5zID0geydfZGVmYXVsdF8nOiBkZWZhdWx0TlN9XG4gICAgICByZXR1cm4gbnNbcHJlZml4XSB8fCBkb2N1bWVudEVsZW1lbnQubG9va3VwTmFtZXNwYWNlVVJJKHByZWZpeClcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzb2x2ZShwYXRoLCByb290LCByZXNvbHZlcilcbn1cblxuXG4vLyBHZXQgdGhlIFhQYXRoIG5vZGUgbmFtZS5cbmZ1bmN0aW9uIG5vZGVOYW1lKG5vZGUpIHtcbiAgc3dpdGNoIChub2RlLm5vZGVOYW1lKSB7XG4gIGNhc2UgJyN0ZXh0JzogcmV0dXJuICd0ZXh0KCknXG4gIGNhc2UgJyNjb21tZW50JzogcmV0dXJuICdjb21tZW50KCknXG4gIGNhc2UgJyNjZGF0YS1zZWN0aW9uJzogcmV0dXJuICdjZGF0YS1zZWN0aW9uKCknXG4gIGRlZmF1bHQ6IHJldHVybiBub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKClcbiAgfVxufVxuXG5cbi8vIEdldCB0aGUgb3JkaW5hbCBwb3NpdGlvbiBvZiB0aGlzIG5vZGUgYW1vbmcgaXRzIHNpYmxpbmdzIG9mIHRoZSBzYW1lIG5hbWUuXG5mdW5jdGlvbiBub2RlUG9zaXRpb24obm9kZSkge1xuICBsZXQgbmFtZSA9IG5vZGUubm9kZU5hbWVcbiAgbGV0IHBvc2l0aW9uID0gMVxuICB3aGlsZSAoKG5vZGUgPSBub2RlLnByZXZpb3VzU2libGluZykpIHtcbiAgICBpZiAobm9kZS5ub2RlTmFtZSA9PT0gbmFtZSkgcG9zaXRpb24gKz0gMVxuICB9XG4gIHJldHVybiBwb3NpdGlvblxufVxuXG5cbi8vIEZpbmQgYSBzaW5nbGUgbm9kZSB3aXRoIFhQYXRoIGBwYXRoYFxuZnVuY3Rpb24gcmVzb2x2ZShwYXRoLCByb290LCByZXNvbHZlcikge1xuICB0cnkge1xuICAgIC8vIEFkZCBhIGRlZmF1bHQgdmFsdWUgdG8gZWFjaCBwYXRoIHBhcnQgbGFja2luZyBhIHByZWZpeC5cbiAgICBsZXQgbnNwYXRoID0gcGF0aC5yZXBsYWNlKC9cXC8oPyFcXC4pKFteXFwvOlxcKF0rKSg/PVxcL3wkKS9nLCAnL19kZWZhdWx0XzokMScpXG4gICAgcmV0dXJuIHBsYXRmb3JtUmVzb2x2ZShuc3BhdGgsIHJvb3QsIHJlc29sdmVyKVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICByZXR1cm4gZmFsbGJhY2tSZXNvbHZlKHBhdGgsIHJvb3QpXG4gIH1cbn1cblxuXG4vLyBGaW5kIGEgc2luZ2xlIG5vZGUgd2l0aCBYUGF0aCBgcGF0aGAgdXNpbmcgdGhlIHNpbXBsZSwgYnVpbHQtaW4gZXZhbHVhdG9yLlxuZnVuY3Rpb24gZmFsbGJhY2tSZXNvbHZlKHBhdGgsIHJvb3QpIHtcbiAgbGV0IHN0ZXBzID0gcGF0aC5zcGxpdChcIi9cIilcbiAgbGV0IG5vZGUgPSByb290XG4gIHdoaWxlIChub2RlKSB7XG4gICAgbGV0IHN0ZXAgPSBzdGVwcy5zaGlmdCgpXG4gICAgaWYgKHN0ZXAgPT09IHVuZGVmaW5lZCkgYnJlYWtcbiAgICBpZiAoc3RlcCA9PT0gJy4nKSBjb250aW51ZVxuICAgIGxldCBbbmFtZSwgcG9zaXRpb25dID0gc3RlcC5zcGxpdCgvW1xcW1xcXV0vKVxuICAgIG5hbWUgPSBuYW1lLnJlcGxhY2UoJ19kZWZhdWx0XzonLCAnJylcbiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uID8gcGFyc2VJbnQocG9zaXRpb24pIDogMVxuICAgIG5vZGUgPSBmaW5kQ2hpbGQobm9kZSwgbmFtZSwgcG9zaXRpb24pXG4gIH1cbiAgcmV0dXJuIG5vZGVcbn1cblxuXG4vLyBGaW5kIGEgc2luZ2xlIG5vZGUgd2l0aCBYUGF0aCBgcGF0aGAgdXNpbmcgYGRvY3VtZW50LmV2YWx1YXRlYC5cbmZ1bmN0aW9uIHBsYXRmb3JtUmVzb2x2ZShwYXRoLCByb290LCByZXNvbHZlcikge1xuICBsZXQgZG9jdW1lbnQgPSBnZXREb2N1bWVudChyb290KVxuICBsZXQgciA9IGRvY3VtZW50LmV2YWx1YXRlKHBhdGgsIHJvb3QsIHJlc29sdmVyLCBGSVJTVF9PUkRFUkVEX05PREVfVFlQRSwgbnVsbClcbiAgcmV0dXJuIHIuc2luZ2xlTm9kZVZhbHVlXG59XG5cblxuLy8gRmluZCB0aGUgY2hpbGQgb2YgdGhlIGdpdmVuIG5vZGUgYnkgbmFtZSBhbmQgb3JkaW5hbCBwb3NpdGlvbi5cbmZ1bmN0aW9uIGZpbmRDaGlsZChub2RlLCBuYW1lLCBwb3NpdGlvbikge1xuICBmb3IgKG5vZGUgPSBub2RlLmZpcnN0Q2hpbGQgOyBub2RlIDsgbm9kZSA9IG5vZGUubmV4dFNpYmxpbmcpIHtcbiAgICBpZiAobm9kZU5hbWUobm9kZSkgPT09IG5hbWUgJiYgLS1wb3NpdGlvbiA9PT0gMCkgYnJlYWtcbiAgfVxuICByZXR1cm4gbm9kZVxufVxuIl19