使用javascript将相对XPath转换为绝对XPath

wz8daaqr  于 2022-12-25  发布在  Java
关注(0)|答案(2)|浏览(209)

有没有可能用javascript得到一个给定dom节点相对路径的绝对xpath?
我找到的最接近的方法是获取节点的xpath:Get Xpath from the org.w3c.dom.Node
此外,我得到了没有唯一标识符的节点的相对xpath,你知道如何解决这个问题吗?
例如,对于:

<p>DUKE SOLINUS</p>
 <div>
 <p>AEGEON</p> 
 </div>

并且对于所选择的单词“杜克”和“AEGEON”,我分别得到xpath“/p[1]"和“/div[1]/p[1]”,当将它们传递给document.evaluate函数时,它们都求值为相同的节点“DUKESOLINUS”。因此,我只有这些相对xpath,并且没有节点。我想要的是评估这些到正确节点的相对XPath,即本例中的两个不同节点(杜克索利纳斯和爱琴海)。
更具体地说,xpath取自json注解对象:http://docs.annotatorjs.org/en/v1.2.x/annotation-format.html
任何帮助都将不胜感激!非常感谢!

92dk7w1h

92dk7w1h1#

这个函数将找到一个到给定节点的绝对xpath,如果节点的顺序改变了,或者节点被添加或删除了,那么这个函数就不起作用了,但是对于静态内容来说应该没问题。

function getXpathOfNode(domNode,bits) {
  // uses cardinality.  Will not work if any nodes are added/moved/removed in the DOM.  Fine for static stuff.
  bits = bits ? bits : [];
  var c = 0;
  var b = domNode.nodeName;
  var p = domNode.parentNode;

  if (p) {
    var els = p.getElementsByTagName(b);
    if (els.length >  1) {
      while (els[c] !== domNode) c++;
      b += "[" + (c+1) + "]";
    }
    bits.push(b);
    return getXpathOfNode(p, bits);
  }
  
  //bits.push(b);  // this is #document.  Probably dont need it.
  return bits.reverse().join("/");
}
// testing
var xp = getXpathOfNode(document.getElementById("pickme"));
var r = document.getElementById("result");
r.innerHTML = "the xpath is " + xp + "<br>";
var result =  document.evaluate(xp, document, null, XPathResult.ANY_TYPE, null);
r.innerHTML += "the chosen node contains - " + result.iterateNext().innerHTML;
<div>
<div>junk</div>
<span>irrelevant</span>
<div>pointless
<div>
<div id="pickme">this is the test node</div><span>don't read this</span></div>
<br><br>
<div id="result"></div>
</div>
uajslkp6

uajslkp62#

背景:我正在做一个项目,我需要知道目标Parent Node的相对XPath。我修改了上面提供的答案@James以达到我想要的效果。**下面是获取ParentNode(mainNode)到子Node的相对XPath的代码。**调用函数时可以忽略标记,它在执行时用于递归调用自身。

function getRealtiveXPathToChild(childNode, mainNode, Tags) {
  const mainParent = mainNode.parentNode;
  Tags = Tags ? Tags : [];
  let currTag = childNode.tagName;
  const currParent = childNode.parentNode;

  if (currParent && mainParent !== currParent) {
    var els = currParent.querySelectorAll(`:scope > ${currTag}`);

    els.forEach((el, idx) => {
      if (els.length > 1 && el === childNode) {
        currTag += "[" + (idx + 1) + "]";
      }
    });

    Tags.push(currTag);
    return this.getRealtiveXPathToChild(currParent, mainNode, Tags);
  }

  return Tags.reverse().join("/");
}

现在,关于您的情况和您提供的示例,其中您只有relative xpath和**,没有元素节点可供使用。您希望从已经拥有的relative xpaths中获取absoute XPath。您可以做的是从相对xpath中获取元素**,然后使用该元素获取其绝对xpath。希望它能有所帮助。

/** 
* Get The Element from the relative XPath
* Add double forward slashes at the beginning of the relative XPath
*/ 
const el = getElementByXpath(`//div[1]/p[1]`);
const absolutePath = getAbsoluteXPathFromNode(el);

function getElementByXpath(path, node) {
  return document.evaluate(
    path,
    node ? node : document,
    null,
    XPathResult.FIRST_ORDERED_NODE_TYPE,
    null
  ).singleNodeValue;
}

/**
 *  The function below is from another answer on this site.
 * @ref : https://stackoverflow.com/questions/9197884/how-do-i-get-the-xpath-of-an-element-in-an-x-html-file
 */
function getAbsoluteXPathFromNode(node) {
  var comp,
    comps = [];
  var parent = null;
  var xpath = "";
  var getPos = function (node) {
    var position = 1,
      curNode;
    if (node.nodeType === Node.ATTRIBUTE_NODE) {
      return null;
    }
    for (
      curNode = node.previousSibling;
      curNode;
      curNode = curNode.previousSibling
    ) {
      if (curNode.nodeName === node.nodeName) {
        ++position;
      }
    }
    return position;
  };

  if (node instanceof Document) {
    return "/";
  }

  for (
    ;
    node && !(node instanceof Document);
    node =
      node.nodeType === Node.ATTRIBUTE_NODE
        ? node.ownerElement
        : node.parentNode
  ) {
    comp = comps[comps.length] = {};

    /*eslint default-case: "error"*/
    switch (node.nodeType) {
      case Node.TEXT_NODE:
        comp.name = "text()";
        break;
      case Node.ATTRIBUTE_NODE:
        comp.name = "@" + node.nodeName;
        break;
      case Node.PROCESSING_INSTRUCTION_NODE:
        comp.name = "processing-instruction()";
        break;
      case Node.COMMENT_NODE:
        comp.name = "comment()";
        break;
      case Node.ELEMENT_NODE:
        comp.name = node.nodeName;
        break;
      // No Default
    }
    comp.position = getPos(node);
  }

相关问题