我可以从org.w3c.dom.Node获取完整的xpath吗?
说当前节点指向xml文档中间的某些位置。我想提取该元素的xpath。
我正在寻找的输出xpath是//parent/child1/chiild2/child3/node
。节点xpath的父节点。只需忽略具有表达式并指向同一节点的xpath。
答案 0 :(得分:13)
获取XPath没有通用方法,主要是因为没有一个通用XPath可以识别文档中的特定节点。在某些模式中,节点将由属性唯一标识(id
,name
可能是最常见的属性。)在其他模式中,每个元素的名称(即标记)足以唯一标识节点。在一些(不太可能,但可能)的情况下,没有一个唯一的名称或属性将您带到特定节点,因此您需要使用基数(获得第一个孩子的第n个孩子)。 ..)。
修改强>:
在大多数情况下,创建依赖于模式的函数来为给定节点组装XPath并不困难。例如,假设您有一个文档,其中每个节点都由id
属性唯一标识,并且您没有使用名称空间。然后(我认为)以下伪Java将根据这些属性返回XPath。 (警告:我没有测试过这个。)
String getXPath(Node node)
{
Node parent = node.getParent();
if (parent == null) {
return "/" + node.getTagName();
}
return getXPath(parent) + "/" + "[@id='" + node.getAttribute("id") + "']";
}
答案 1 :(得分:11)
我在jOOX后面的公司工作,这是一个为Java标准DOM API提供许多有用扩展的库,模仿jquery API。使用jOOX,您可以获得这样的任何元素的XPath:
String path = $(element).xpath();
上面的路径将是这样的
/document[1]/library[2]/books[3]/book[1]
答案 2 :(得分:7)
我从中获取了此代码 Mikkel Flindt post&修改它以便它可以用于属性节点。
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();
}
答案 3 :(得分:7)
对我来说,这个最好用(使用org.w3c.dom元素):
String getXPath(Node node)
{
Node parent = node.getParentNode();
if (parent == null)
{
return "";
}
return getXPath(parent) + "/" + node.getNodeName();
}
答案 4 :(得分:3)
一些专门用于XML的IDE将为您做到这一点。
这是最着名的
例如在oXygen中,您可以右键单击XML文档的元素部分,上下文菜单将有一个“Copy Xpath”选项。
还有许多Firefox附加组件(例如XPather)很乐意为您完成工作。对于Xpather,您只需单击网页的一部分并在上下文菜单中选择'在XPather中展示'你已经完成了。
但是,正如丹在他的回答中指出的那样,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>
我列出的工具不生成
/root/nodeB[@cond='thisOne']/subnodeX[@id='MyCondition']
例如对于一个html页面,你最终会得到一个非常无用的表达式:
/html/body/div[6]/p[3]
这是可以预料的。如果他们必须生成谓词,他们如何知道哪个条件是相关的?有数以万计的可能性。
答案 5 :(得分:-1)
这样的东西会给你一个简单的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);
}