2015-06-26 64 views
1

我有一段代碼爲節點生成xpath。但它不會創建它的數組結構。例如,如果一個元素具有兩個同名的元素,我需要提供索引以適當地指向它們。下面是一個例子。現在如何使用java爲XML中的節點生成Xpath?

<abc> 
    <def> 
    </hij> 
    </def> 
    <def> 
    </lmn> 
    </def> 
</abc> 

,得到的XPath爲hij,我需要這樣的:

//abc[1]/def[1]/hij 

要獲得的XPath lmn,我需要這樣的:

//abc[1]/def[2]/lmn 

我有一段代碼,它只會給我//abc/def/hij//abc/def/lmn

private String getXPath(Node root, String elementName) 
    { 
     for (int i = 0; i < root.getChildNodes().getLength(); i++) 
     { 
      Node node = root.getChildNodes().item(i); 
      if (node instanceof Element) 
      { 
       if (node.getNodeName().equals(elementName)) 
       { 
        return "\\" + node.getNodeName(); 
       } 
       else if (node.getChildNodes().getLength() > 0) 
       { 
        if(map.containsKey(node.getNodeName())) 
         map.put(node.getNodeName(), map.get(node.getNodeName())+1); 
        else 
         map.put(node.getNodeName(), 1); 

        this.xpath = getXPath(node, elementName); 
        if (this.xpath != null){ 
         return "\\" + node.getNodeName() +"["+map.get(node.getNodeName())+"]"+ this.xpath; 
        } 
       } 
      } 
     } 

     return null; 
    } 

有人可以幫我追加這個數組結構嗎?

回答

0
<abc> 
    <def> 
    </hij> 
    </def> 
    <def> 
    </lmn> 
    </def> 
</abc> 

在這裏。您正在關閉

</hij> 

</lmn> 

,而無需打開它們。如果您在abc之前打開它們,則您無法在abc內關閉它們。基本上:你不能糾纏他們。 打開一個,打開第二個,關閉第二個,關閉一個。切勿以其他方式。

這可能導致你的錯誤

0

我無法修復你的代碼中的問題,因爲它是不完整的,例如被定義地圖在哪裏?另請參閱有關您格式錯誤的輸入的其他答案。

使該HIJ和LMN應該是短標記的假設,這裏是一個完整的解決方案。

  • 我使用了使用getParentNode()向上導航樹的方法。
  • 我已經包含XPath測試以檢查生成的表達式是否返回同一節點
  • 擴展輸入以包含同一級別不同名稱的元素。

代碼

public class Test { 

    private static String getXPath(Node root) { 
     Node current = root; 
     String output = ""; 
     while (current.getParentNode() != null) { 
      Node parent = current.getParentNode(); 
      if (parent != null && parent.getChildNodes().getLength() > 1) { 
       int nthChild = 1; 
       Node siblingSearch = current; 
       while ((siblingSearch = siblingSearch.getPreviousSibling()) != null) { 
        // only count siblings of same type 
        if (siblingSearch.getNodeName().equals(current.getNodeName())) { 
         nthChild++; 
        } 
       } 
       output = "/" + current.getNodeName() + "[" + nthChild + "]" + output; 
      } else { 
       output = "/" + current.getNodeName() + output; 
      } 
      current = current.getParentNode(); 
     } 
     return output; 
    } 

    public static void main(String[] args) throws Exception { 

     String input = "<abc><def><hij /></def><def><lmn /><xyz /><lmn /></def></abc>"; 
     Document root = DocumentBuilderFactory.newInstance() 
       .newDocumentBuilder() 
       .parse(new InputSource(new StringReader(input))); 

     test(root.getDocumentElement(), root); 
    } 

    private static void test(Node node, Document doc) throws Exception { 
     String expression = getXPath(node); 
     Node result = (Node) XPathFactory.newInstance().newXPath() 
       .compile(expression).evaluate(doc, XPathConstants.NODE); 
     if (result == node) { 
      System.out.println("Test OK : " + expression); 
     } else { 
      System.out.println("Test Fail: " + expression); 
     } 
     for (int i = 0; i < node.getChildNodes().getLength(); i++) { 
      test(node.getChildNodes().item(i), doc); 
     } 
    } 
} 

輸出

Test OK : /abc 
Test OK : /abc/def[1] 
Test OK : /abc/def[1]/hij 
Test OK : /abc/def[2] 
Test OK : /abc/def[2]/lmn[1] 
Test OK : /abc/def[2]/xyz[1] 
Test OK : /abc/def[2]/lmn[2]