2012-01-30 61 views
0

我們如何獲得FreeMarker中節點的XPath。我想知道synatax。 就像我正在處理一個節點並希望以XML獲取其地址一樣。FreeMarker XML Xpath

類似於:node?node_xpath。

回答

1

沒有這樣的東西存在開箱即用。你可以爲它編寫一個自定義方法(TemplateMethodModelEx實現)。無論如何你需要什麼樣的路徑?像/node()[0]/node()[3]/node()[2]?我相信W3C DOM API沒有方法來查詢節點的索引,因此您必須掃描節點父節點的子節點以查找其索引。 (這是一個DOM限制,而不是FreeMarker的限制。)或者如果你對這個模式有更多的瞭解,你可能需要像/foo/bar[@id=123]/baaz這樣的東西,但這顯然不是一個通用的功能。

0

試試這個:

public class GetXPathFromNode implements TemplateMethodModelEx { 

public Object exec(List args) throws TemplateModelException { 

    if(args.size() != 1){ 
     throw new TemplateModelException("Please specify one xml node."); 
    } 

    NodeModel node = (NodeModel) args.get(0); 

    return getXPath(node.getNode()); 

} 

private String getXPath(Node node) { 
    StringBuilder sb = new StringBuilder("/"); 
    String attribute = ""; 
    if(node.getNodeType() == Node.ATTRIBUTE_NODE){ 
     attribute = "/@" + node.getNodeName(); 
     Attr attr = (Attr) node; 
     node = attr.getOwnerElement(); 
    } 

    sb.append(node.getNodeName()) 
    .append("[").append(getNodeIndex(node)).append("]").append(attribute); 

    return renderNodeXpath(node, sb).toString(); 
} 

private StringBuilder renderNodeXpath(Node node, StringBuilder path){ 

    Node parentNode = node.getParentNode(); 
    if(parentNode != null && parentNode.getNodeType() != Node.DOCUMENT_NODE){ 
     StringBuilder sb2 = new StringBuilder("/"); 
     sb2.append("[").append(getNodeIndex(parentNode)).append("]"); 
     path.insert(0,sb2); 
     return renderNodeXpath(parentNode, path); 

    } 
    return path; 

} 

private int getNodeIndex(Node childNode) { 

    Node parentNode = childNode.getParentNode(); 
    if(parentNode == null){ 
     return 1; 
    } 


    int index = 1; 
    for(int i = 0; parentNode.getChildNodes().getLength() >= i; i++){ 
     Node node = parentNode.getChildNodes().item(i); 

     if(node.isSameNode(childNode)){ 
      return index; // this is used to ignore empty text nodes. 
     } 
     if(node.getNodeType() != Node.TEXT_NODE){ 
      index++; 
     } 
    } 

    return 1; 
} 

}