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()没有意义。基本上,该函数只返回1getElementIdx(element)
应该将element\u节点的所有以前的同级节点计算在内,并且previousSibling.tagname
与element.tagname
匹配。所以我最终会得到类似的/html/body/p[3]。@Kim:那么异常处理呢?如果第一个“上一个兄弟姐妹”不是一个元素,这就解释了为什么你得到的计数是1。。。例外情况将是thr