我写了我想要实现的目标。但是,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;
}
答案 0 :(得分:6)
您的标题谈到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_NODE)
代替instanceof
测试。
答案 1 :(得分:4)
Dom4j xpath支持非常好,您可以通过提供xpath表达式来访问任何元素 但是我不确定反向是否正确,即是否给出了一个元素,你可以导出xpath表达式。
请参阅http://www.docjar.com/projects/dom4j-1.6.1-code.html
处的api请注意避免www.dom4j.org,它似乎被某种垃圾链接农场所淹没。
答案 2 :(得分:1)
我玩XOM library,它有一个很好的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)));
}
}
我用于测试的文档:
<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>
远非完美,但我希望这有帮助! : - )