Я играл с библиотекой XOM , которая имеет хороший 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>
Далеко не идеально, но я надеюсь, что это поможет!: -)