如何使用java为XML中的节点生成Xpath?

时间:2015-06-26 11:46:21

标签: java xml xpath

我有一段代码为节点生成xpath。但它并没有创建它的数组结构。例如,如果一个元素有两个具有相同名称的元素,我需要提供索引以适当地指向它们。它的例子如下。

<abc>
  <def>
     </hij>
  </def>
  <def>
     </lmn>
  </def>
</abc>

现在,要获得hij的xpath,我需要这样的东西:

//abc[1]/def[1]/hij

要获取lmn的xpath,我需要这样的东西:

//abc[1]/def[2]/lmn

我有一段代码只会给我//abc/def/hij//abc/def/lmn

private String getXPath(Node root, String elementName)
    {
        for (int i = 0; i < root.getChildNodes().getLength(); i++)
        {
            Node node = root.getChildNodes().item(i);
            if (node instanceof Element)
            {
                if (node.getNodeName().equals(elementName))
                {
                    return "\\" + node.getNodeName();
                }
                else if (node.getChildNodes().getLength() > 0)
                {
                    if(map.containsKey(node.getNodeName()))
                        map.put(node.getNodeName(), map.get(node.getNodeName())+1);
                    else
                        map.put(node.getNodeName(), 1);

                    this.xpath = getXPath(node, elementName);
                    if (this.xpath != null){
                        return "\\" + node.getNodeName() +"["+map.get(node.getNodeName())+"]"+ this.xpath;
                    }
                }
            }
        }

        return null;
    }

有人可以帮我添加数组结构吗?

2 个答案:

答案 0 :(得分:0)

<abc>
  <def>
    </hij>
  </def>
  <def>
    </lmn>
  </def>
</abc>

在这里。你正在结束

</hij> 

</lmn>

没有打开它们。如果你在abc之前打开它们,你就无法在abc内关闭它们。 基本上:你不能把它们交织在一起。 打开一个,打开第二个,关闭第二个,关闭一个。从来没有以其他方式。

这可能会导致您的错误

答案 1 :(得分:0)

我无法在问题中修复您的代码,因为它不完整,例如地图定义在哪里?另请参阅有关您的格式错误输入的其他答案。

假设hij和lmn应该是短标签,这是一个完整的解决方案。

  • 我使用了使用getParentNode()导航树的方法。
  • 我已经包含XPath测试来检查生成的表达式是否返回相同的节点
  • 扩展输入以包含同一级别的不同名称的元素。

代码

public class Test {

    private static String getXPath(Node root) {
        Node current = root;
        String output = "";
        while (current.getParentNode() != null) {
            Node parent = current.getParentNode();
            if (parent != null && parent.getChildNodes().getLength() > 1) {
                int nthChild = 1;
                Node siblingSearch = current;
                while ((siblingSearch = siblingSearch.getPreviousSibling()) != null) {
                    // only count siblings of same type
                    if (siblingSearch.getNodeName().equals(current.getNodeName())) {
                        nthChild++;
                    }
                }
                output = "/" + current.getNodeName() + "[" + nthChild + "]" + output;
            } else {
                output = "/" + current.getNodeName() + output;
            }
            current = current.getParentNode();
        }
        return output;
    }

    public static void main(String[] args) throws Exception {

        String input = "<abc><def><hij /></def><def><lmn /><xyz /><lmn /></def></abc>";
        Document root = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .parse(new InputSource(new StringReader(input)));

        test(root.getDocumentElement(), root);
    }

    private static void test(Node node, Document doc) throws Exception {
        String expression = getXPath(node);
        Node result = (Node) XPathFactory.newInstance().newXPath()
                .compile(expression).evaluate(doc, XPathConstants.NODE);
        if (result == node) {
            System.out.println("Test OK  : " + expression);
        } else {
            System.out.println("Test Fail: " + expression);
        }
        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
            test(node.getChildNodes().item(i), doc);
        }
    }
}

输出

Test OK  : /abc
Test OK  : /abc/def[1]
Test OK  : /abc/def[1]/hij
Test OK  : /abc/def[2]
Test OK  : /abc/def[2]/lmn[1]
Test OK  : /abc/def[2]/xyz[1]
Test OK  : /abc/def[2]/lmn[2]