Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:获取org.w3c.dom文档中元素的xpath_Java_Dom - Fatal编程技术网

Java:获取org.w3c.dom文档中元素的xpath

Java:获取org.w3c.dom文档中元素的xpath,java,dom,Java,Dom,我已经写下了我想要达到的目标。但是,getElementIdx()函数没有返回正确的计数。getPreviousSibling()有问题,但我不知道为什么 public static String getElementXpath(DOMElement elt){ String path = ""; try{ for (; elt != null; elt = (DOMElement) elt.getParentNode()){

我已经写下了我想要达到的目标。但是,
getElementIdx()
函数没有返回正确的计数。
getPreviousSibling()
有问题,但我不知道为什么

public static String getElementXpath(DOMElement elt){
        String path = ""; 

        try{
            for (; elt != null; elt = (DOMElement) elt.getParentNode()){
                int idx = getElementIdx(elt);
                String xname = elt.getTagName().toString();

                if (idx >= 1) xname += "[" + idx + "]";
                path = "/" + xname + path;  
            }
        }catch(Exception ee){
        }
        return path;                            
    }

    public static int getElementIdx(DOMElement elt) {
      int count = 1;
      try{

         for (DOMElement sib = (DOMElement) elt.getNextSibling(); sib != null; sib = (DOMElement) sib.getNextSibling())
            {
                if(sib.getTagName().equals(elt.getTagName())){
                    count++;
                }
            }
      }catch(Exception ee){      
      }
        return count;
    }

Dom4j xpath支持非常好,您可以通过提供xpath表达式来访问任何元素。
但是,我不确定反过来是否正确,即给定一个元素是否可以派生xpath表达式

请参阅

注意:www.dom4j.org,它似乎被某种垃圾链接场劫持了。

我使用了,它有一个很好的API。步行完成这项工作比使用XSLT更困难。以下内容将帮助您开始。请注意,缺少兄弟位置的内容

接口:

package milu.calcxpath;
import nu.xom.Node;
import nu.xom.ParentNode;

public interface Calculator
{
    public void buildXPath( Node node, StringBuilder sb );
    public void buildXPath( ParentNode node, StringBuilder sb );
}
实现类:

package milu.calcxpath;
import nu.xom.Attribute;
import nu.xom.Comment;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Node;
import nu.xom.ParentNode;
import nu.xom.ProcessingInstruction;
import nu.xom.Text;

public class SimpleCalculator implements Calculator
{
    @Override
    public void buildXPath( Node node, StringBuilder sb )
    {
        if ( null == node )
            return;
        if ( this.findShortCut(node, sb) )
            return;

        ParentNode parent = node.getParent();
        boolean doParents = true;
        if ( parent instanceof Element )
            if ( this.findShortCut((Element) parent, sb) )
                doParents = false;
        if ( doParents )
            this.buildXPath(parent, sb);

        if ( node instanceof Element ) {
            String name = ( (Element) node ).getLocalName();
            sb.append("/" + name);
        } else if ( node instanceof Attribute ) {
            sb.append("/@" + ( (Attribute) node ).getLocalName());
        } else if ( node instanceof Text ) {
            sb.append("/text()");
        } else if ( node instanceof Comment ) {
            sb.append("/comment()");
        } else if ( node instanceof ProcessingInstruction ) {
            sb.append("/processing-instruction()");
        }
    }

    protected boolean findShortCut( Node node, StringBuilder sb )
    {
        return false;
    }

    @Override
    public void buildXPath( ParentNode node, StringBuilder sb )
    {
        if ( null == node )
            return;
        ParentNode parent = node.getParent();
        if ( null == parent )
            return;
        else if ( parent instanceof Document ) {
            ;
        } else { // element
            if ( ! this.findShortCut((Element) parent, sb) )
                this.buildXPath(parent, sb);
        }
        sb.append("/");
        sb.append(( (Element) node ).getLocalName());
    }

    protected boolean findShortCut( Element elm, StringBuilder sb )
    {
        return false;
    }
}
另一个,扩展它。这是@id的东西

package milu.calcxpath;
import nu.xom.Attribute;
import nu.xom.Element;
import nu.xom.Node;

public class IdShortCutCalculator extends SimpleCalculator
{
    final private static String ID = "id";

    @Override
    protected boolean findShortCut( Node node, StringBuilder sb )
    {
        if ( ! ( node instanceof Attribute ) )
            return false;
        Attribute attr = (Attribute) node;
        if ( ! attr.getLocalName().equals(ID) )
            return false;
        sb.append("//@id='");
        sb.append(attr.getValue());
        sb.append("'");
        return true;
    }

    @Override
    protected boolean findShortCut( Element elm, StringBuilder sb )
    {
        String val = elm.getAttributeValue(ID);
        if ( null == val )
            return false;
        sb.append("//*[@id='");
        sb.append(val);
        sb.append("']");
        return true;
    }
}
另一个类作为前端:

package milu.calcxpath;

import nu.xom.Node;

public class XPathCalculator
{
    private Calculator calculator;

    public XPathCalculator(Calculator calc) {
        this.calculator = calc;
    }

    public String calculateXPath( Node node )
    {
        StringBuilder sb = new StringBuilder();
        this.calculator.buildXPath(node, sb);
        return sb.toString();
    }
}
和一个测试脚本:

package milu.calcxpath;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Nodes;

public class Test
{
    public static void main( String[] args ) throws Exception
    {
        Builder builder = new Builder();
        Document doc = builder.build(Test.class.getResourceAsStream("/milu/calcxpath/eins.xml"));
        Calculator calc;
        // calc = new SimpleCalculator();
        calc = new IdShortCutCalculator();
        XPathCalculator xpc = new XPathCalculator(calc);
        show(xpc, doc, "//*");
        show(xpc, doc, "//@*");
        show(xpc, doc, "//node()");
        show(xpc, doc, "//processing-instruction()");
        show(xpc, doc, "//*//processing-instruction()");
    }

    private static void show( XPathCalculator xpc, Document doc, String xpath )
    {
        System.out.println("==========================");
        System.out.println("    " + xpath);
        Nodes nodes = doc.query(xpath);
        int size = nodes.size();
        for ( int i = 0; i < size; i++ )
            System.out.println(xpc.calculateXPath(nodes.get(i)));
    }
}
package milu.calcxpath;
导入nu.xom.Builder;
导入nu.xom.Document;
导入nu.xom.Nodes;
公开课考试
{
公共静态void main(字符串[]args)引发异常
{
Builder=新的Builder();
Document doc=builder.build(Test.class.getResourceAsStream(“/milu/calcxpath/eins.xml”);
计算器计算器;
//calc=新的SimpleCalculator();
calc=新的IdShortCutCalculator();
XPathCalculator xpc=新的XPathCalculator(计算);
显示(xpc,文件“/*”);
显示(xpc,doc,“/@*”);
显示(xpc,doc,“//node()”;
显示(xpc,doc,“//处理指令()”;
显示(xpc,doc,“//*//处理-指令()”;
}
私有静态void显示(XPathCalculator xpc、文档文档、字符串xpath)
{
System.out.println(“==============================================”);
System.out.println(“+xpath”);
Nodes=doc.query(xpath);
int size=nodes.size();
对于(int i=0;i
我用于测试的文档:

<Urmel>
  <!-- spukt im Schloss -->
  <Monster xmlns="urn:X-Monster">
    <Gurke>
      <?Garten eins="zwei" drei="vier"?>
      <Heini Hecht="toll">
        <eins>eins</eins>
        <zwei id="ich-bin-die-zwei">zwei</zwei>
        <drei letzt="1">drei</drei>
      </Heini>
      <!-- Es kann nur einen geben :-) -->
    </Gurke>
    <Tomate id="pomodoro">
      <eene/>
      <meene/>
      <miste>Auweia!</miste>
      <aa>
        <bb>
          <cc>dd</cc>
        </bb>
      </aa>
    </Tomate>
  </Monster>
</Urmel>

埃因斯
茨威
德雷
奥维亚!
dd

远非完美,但我希望这能有所帮助!:-)

您的标题谈到了
getPreviousSibling()
,但您的代码只使用
getNextSibling()
-为什么?我不明白您为什么要使用
getNextSibling()
。。。您想知道有多少同名元素位于当前元素之前,而不是有多少位于当前元素之后

事实上,您正在捕获并接受异常也是非常可疑的。。。你为什么要这么做?如果有异常,该方法不应该以异常终止吗

您可能还应该考虑到
getPreviousSibling
可能不返回元素,例如,它可能返回文本节点。您将希望跳过这些-当前您将得到一个异常,它将终止循环并返回当前计数

如果这些都没有帮助,请发布一些示例XML,指出一个节点,并说明代码当前返回的内容(以及发布更新的代码)。仅仅说它没有返回正确的计数,远不如说它返回了什么,以及你期望它返回什么有用

编辑:这就是我希望代码的样子:

public static int getElementIndex(Element original) {
  int count = 1;

  for (Node node = original.getPreviousSibling(); node != null;
       node = node.getPreviousSibling()) {
    if (node instanceof Element) {
      Element element = (Element) node;
      if (element.getTagName().equals(original.getTagName()) {
        count++;
      }
    }
  }

  return count;
}

您还可以使用
if(node.getNodeType()==node.ELEMENT\u node)
而不是
instanceof
测试。

是的,这在Dom4j中是可能的:使用
node.getUniquePath()
。但是,您需要首先将W3C文档转换为Dom4j文档。实际上,这很简单(只需使用
new DOMReader().read(w3cDocument)
),但这不是一个非常有效的解决方案,尤其是在必须重复进行转换的情况下。有什么更好的方法?现在,我只是想把这个Javascript函数翻译成Java@克里斯,如果Dom4j被反复使用怎么办?这会很慢还是浪费内存?@Kim:不会,如果您使用Dom4j而不是W3C-DOM而不在它们之间进行转换,那么就不会有性能损失。@Chris,我正在进行翻译。我已经写了一半的函数来从org.w3c.dom.domdocument构造基数xpath,并读取xpath。我应该继续追求还是转到dom4j。如果反复翻译w3c dom文档的代价还不错,那么我也可以……请更详细地描述您希望获得的XPath格式,或者只说明您希望函数返回的XPath表达式的用途。我注意到JavaScript函数专门处理@id。你想不想特别注意@id?另外,在你的第一句话中,你在写
getElementByXpath()
,而我认为你想
getxpathforement()
-你能澄清一下吗?迈克尔,是的,这是正确的。我想关注@id。所以我会喜欢xpath格式,如下所示
//duv[@id=“meni”]/span/a[2]
.com.collaxa.xml.XPathUtils.getxpathexpromnode(Node)这不是你要找的吗?对不起。第一条评论中的包错误。getXPathExprFromNode(Node)这不是您要找的吗?我创建了一个更简短的版本,但它不能100%工作。我已经更新了我的问题。是的。那是个打字错误。我的意思是只获取以前的兄弟姐妹()。nextsibling()没有意义。基本上,该函数只返回1
getElementIdx(element)
应该将
element\u节点的所有以前的同级节点计算在内,并且
previousSibling.tagname
element.tagname
匹配。所以我最终会得到类似的/html/body/p[3]。@Kim:那么异常处理呢?如果第一个“上一个兄弟姐妹”不是一个元素,这就解释了为什么你得到的计数是1。。。例外情况将是thr