Java 从org.w3c.dom.Node获取Xpath

Java 从org.w3c.dom.Node获取Xpath,java,xml,dom,Java,Xml,Dom,我可以从org.w3c.dom.Node获取完整的xpath吗 假设当前节点指向xml文档中间的某个位置。我想提取该元素的xpath 我要查找的输出xpath是//parent/child1/chiild2/child3/node。节点xpath的父节点。忽略包含表达式并指向同一节点的xpath。没有获取xpath的通用方法,主要是因为没有一个通用xpath来标识文档中的特定节点。在某些模式中,节点将由属性唯一标识(id和name可能是最常见的属性)。在其他模式中,每个元素的名称(即标记)足以唯

我可以从org.w3c.dom.Node获取完整的xpath吗

假设当前节点指向xml文档中间的某个位置。我想提取该元素的xpath


我要查找的输出xpath是
//parent/child1/chiild2/child3/node
。节点xpath的父节点。忽略包含表达式并指向同一节点的xpath。

没有获取xpath的通用方法,主要是因为没有一个通用xpath来标识文档中的特定节点。在某些模式中,节点将由属性唯一标识(
id
name
可能是最常见的属性)。在其他模式中,每个元素的名称(即标记)足以唯一标识节点。在少数(不太可能,但可能)情况下,没有唯一的名称或属性将您带到特定节点,因此您需要使用基数(获取…)的第m个子节点的第n个子节点)

编辑: 在大多数情况下,创建依赖于模式的函数来为给定节点组装XPath并不困难。例如,假设您有一个文档,其中每个节点都由
id
属性唯一标识,并且您没有使用名称空间。然后(我认为)下面的伪Java将基于这些属性返回XPath。(警告:我尚未对此进行测试。)


一些专门研究XML的IDE可以为您做到这一点

这里是最有名的

  • 例如,在oXygen中,您可以右键单击XML文档的元素部分,上下文菜单将有一个选项“复制Xpath”

    还有许多Firefox插件(例如,它将很乐意为您完成这项工作。对于Xpather,您只需单击网页的一部分,然后在上下文菜单中选择“在Xpather中显示”,就完成了

    但是,正如Dan在他的回答中指出的那样,XPath表达式的用途有限。例如,它将不包括谓词,而是看起来像这样

    /root/nodeB[2]/subnodeX[2]
    
    对于像这样的文档

    <root>
       <nodeA>stuff</nodeA>
       <nodeB>more stuff</nodeB>
       <nodeB cond="thisOne">
           <subnodeX>useless stuff</subnodeX>
           <subnodeX id="MyCondition">THE STUFF YOU WANT</subnodeX>
           <subnodeX>more useless stuff</subnodeX>
       </nodeB>
    </root>
    
    例如,对于html页面,您将得到一个非常无用的表达式:

    /html/body/div[6]/p[3]
    

    这是意料之中的。如果他们必须生成谓词,他们怎么知道哪个条件是相关的呢?有无数的可能性。

    我在behind公司工作,这是一个为Java标准DOM API提供许多有用扩展的库,模仿了jOOX。通过jOOX,你可以获得像thi这样的任何元素的XPaths:

    String path = $(element).xpath();
    
    上面的路径将是这样的

    /document[1]/library[2]/books[3]/book[1]
    
    我从 &对其进行了修改,使其可以用于属性节点

    public static String getFullXPath(Node n) {
    // abort early
    if (null == n)
      return null;
    
    // declarations
    Node parent = null;
    Stack<Node> hierarchy = new Stack<Node>();
    StringBuffer buffer = new StringBuffer();
    
    // push element on stack
    hierarchy.push(n);
    
    switch (n.getNodeType()) {
    case Node.ATTRIBUTE_NODE:
      parent = ((Attr) n).getOwnerElement();
      break;
    case Node.ELEMENT_NODE:
      parent = n.getParentNode();
      break;
    case Node.DOCUMENT_NODE:
      parent = n.getParentNode();
      break;
    default:
      throw new IllegalStateException("Unexpected Node type" + n.getNodeType());
    }
    
    while (null != parent && parent.getNodeType() != Node.DOCUMENT_NODE) {
      // push on stack
      hierarchy.push(parent);
    
      // get parent of parent
      parent = parent.getParentNode();
    }
    
    // construct xpath
    Object obj = null;
    while (!hierarchy.isEmpty() && null != (obj = hierarchy.pop())) {
      Node node = (Node) obj;
      boolean handled = false;
    
      if (node.getNodeType() == Node.ELEMENT_NODE) {
        Element e = (Element) node;
    
        // is this the root element?
        if (buffer.length() == 0) {
          // root element - simply append element name
          buffer.append(node.getNodeName());
        } else {
          // child element - append slash and element name
          buffer.append("/");
          buffer.append(node.getNodeName());
    
          if (node.hasAttributes()) {
            // see if the element has a name or id attribute
            if (e.hasAttribute("id")) {
              // id attribute found - use that
              buffer.append("[@id='" + e.getAttribute("id") + "']");
              handled = true;
            } else if (e.hasAttribute("name")) {
              // name attribute found - use that
              buffer.append("[@name='" + e.getAttribute("name") + "']");
              handled = true;
            }
          }
    
          if (!handled) {
            // no known attribute we could use - get sibling index
            int prev_siblings = 1;
            Node prev_sibling = node.getPreviousSibling();
            while (null != prev_sibling) {
              if (prev_sibling.getNodeType() == node.getNodeType()) {
                if (prev_sibling.getNodeName().equalsIgnoreCase(
                    node.getNodeName())) {
                  prev_siblings++;
                }
              }
              prev_sibling = prev_sibling.getPreviousSibling();
            }
            buffer.append("[" + prev_siblings + "]");
          }
        }
      } else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
        buffer.append("/@");
        buffer.append(node.getNodeName());
      }
    }
    // return buffer
    return buffer.toString();
    }          
    
    公共静态字符串getFullXPath(节点n){
    //早早流产
    if(null==n)
    返回null;
    //声明
    节点父节点=null;
    堆栈层次结构=新堆栈();
    StringBuffer=新的StringBuffer();
    //将元素推到堆栈上
    层次推送(n);
    开关(n.getNodeType()){
    案例节点。属性_节点:
    父项=((Attr)n).getOwnerElement();
    打破
    案例节点。元素节点:
    父节点=n.getParentNode();
    打破
    案例节点.文档节点:
    父节点=n.getParentNode();
    打破
    违约:
    抛出新的IllegalStateException(“意外节点类型”+n.getNodeType());
    }
    while(null!=parent&&parent.getNodeType()!=Node.DOCUMENT\u Node){
    //推式堆栈
    hierarchy.push(父级);
    //获取父对象的父对象
    parent=parent.getParentNode();
    }
    //构造xpath
    objectobj=null;
    而(!hierarchy.isEmpty()&&null!=(obj=hierarchy.pop()){
    Node Node=(Node)obj;
    布尔值=假;
    if(node.getNodeType()==node.ELEMENT\u node){
    元素e=(元素)节点;
    //这是根元素吗?
    if(buffer.length()==0){
    //根元素-只需附加元素名
    append(node.getNodeName());
    }否则{
    //子元素-附加斜杠和元素名称
    缓冲区。追加(“/”);
    append(node.getNodeName());
    if(node.hasAttributes()){
    //查看元素是否具有name或id属性
    如果(如属性(“id”)){
    //找到id属性-使用该属性
    append(“[@id=”+e.getAttribute(“id”)+“]”);
    已处理=正确;
    }else if(如hasAttribute(“名称”)){
    //找到name属性-使用该属性
    append(“[@name=”+e.getAttribute(“name”)+“]”);
    已处理=正确;
    }
    }
    如果(!已处理){
    //没有我们可以使用的已知属性-获取同级索引
    int-prev_兄弟姐妹=1;
    Node prev_sibling=Node.getPreviousSibling();
    while(null!=上一个同级){
    if(prev_sibling.getNodeType()==node.getNodeType()){
    if(prev_sibling.getNodeName().equalsIgnoreCase(
    node.getNodeName()){
    上一个++;
    }
    }
    prev_sibling=prev_sibling.getPreviousSibling();
    }
    buffer.append(“[”+上一个兄弟姐妹+“]);
    }
    }
    }else if(node.getNodeType()==node.ATTRIBUTE\u node){
    buffer.append(“/”);
    append(node.getNodeName());
    }
    }
    //返回缓冲区
    返回buffer.toString();
    }          
    
    类似的内容将为您提供一个简单的xpath:

    public String getXPath(Node node) {
        return getXPath(node, "");
    }
    
    public String getXPath(Node node, String xpath) {
        if (node == null) {
            return "";
        }
        String elementName = "";
        if (node instanceof Element) {
            elementName = ((Element) node).getLocalName();
        }
        Node parent = node.getParentNode();
        if (parent == null) {
            return xpath;
        }
        return getXPath(parent, "/" + elementName + xpath);
    }
    

    对我来说,这一个效果最好(使用org.w3c.dom元素):


    除非您想要XPath2.0解决方案(在XPath1.0中,这是不可能的)如果您定义了一组特定的XPath表达式,那么这个问题在一般情况下是无法回答的:存在选择给定XML树的同一节点的无限XPath表达式。@Alejandro:好的。我的XPath中不会有任何表达式。我正在查找XPath 2.0规范本身中的//parent/child1/chiild2/nodeThat:
    string-join(祖先或self::node()/name(),“/”)
    以下堆栈溢出问题可能与您有关:如果第一个return语句返回空字符串,这对我更有效。Oth
    public static String getFullXPath(Node n) {
    // abort early
    if (null == n)
      return null;
    
    // declarations
    Node parent = null;
    Stack<Node> hierarchy = new Stack<Node>();
    StringBuffer buffer = new StringBuffer();
    
    // push element on stack
    hierarchy.push(n);
    
    switch (n.getNodeType()) {
    case Node.ATTRIBUTE_NODE:
      parent = ((Attr) n).getOwnerElement();
      break;
    case Node.ELEMENT_NODE:
      parent = n.getParentNode();
      break;
    case Node.DOCUMENT_NODE:
      parent = n.getParentNode();
      break;
    default:
      throw new IllegalStateException("Unexpected Node type" + n.getNodeType());
    }
    
    while (null != parent && parent.getNodeType() != Node.DOCUMENT_NODE) {
      // push on stack
      hierarchy.push(parent);
    
      // get parent of parent
      parent = parent.getParentNode();
    }
    
    // construct xpath
    Object obj = null;
    while (!hierarchy.isEmpty() && null != (obj = hierarchy.pop())) {
      Node node = (Node) obj;
      boolean handled = false;
    
      if (node.getNodeType() == Node.ELEMENT_NODE) {
        Element e = (Element) node;
    
        // is this the root element?
        if (buffer.length() == 0) {
          // root element - simply append element name
          buffer.append(node.getNodeName());
        } else {
          // child element - append slash and element name
          buffer.append("/");
          buffer.append(node.getNodeName());
    
          if (node.hasAttributes()) {
            // see if the element has a name or id attribute
            if (e.hasAttribute("id")) {
              // id attribute found - use that
              buffer.append("[@id='" + e.getAttribute("id") + "']");
              handled = true;
            } else if (e.hasAttribute("name")) {
              // name attribute found - use that
              buffer.append("[@name='" + e.getAttribute("name") + "']");
              handled = true;
            }
          }
    
          if (!handled) {
            // no known attribute we could use - get sibling index
            int prev_siblings = 1;
            Node prev_sibling = node.getPreviousSibling();
            while (null != prev_sibling) {
              if (prev_sibling.getNodeType() == node.getNodeType()) {
                if (prev_sibling.getNodeName().equalsIgnoreCase(
                    node.getNodeName())) {
                  prev_siblings++;
                }
              }
              prev_sibling = prev_sibling.getPreviousSibling();
            }
            buffer.append("[" + prev_siblings + "]");
          }
        }
      } else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
        buffer.append("/@");
        buffer.append(node.getNodeName());
      }
    }
    // return buffer
    return buffer.toString();
    }          
    
    public String getXPath(Node node) {
        return getXPath(node, "");
    }
    
    public String getXPath(Node node, String xpath) {
        if (node == null) {
            return "";
        }
        String elementName = "";
        if (node instanceof Element) {
            elementName = ((Element) node).getLocalName();
        }
        Node parent = node.getParentNode();
        if (parent == null) {
            return xpath;
        }
        return getXPath(parent, "/" + elementName + xpath);
    }
    
    String getXPath(Node node)
    {
        Node parent = node.getParentNode();
        if (parent == null)
        {
            return "";
        }
        return getXPath(parent) + "/" + node.getNodeName();
    }