2016-06-13 66 views
0

我需要幫助使xpath表達式讀取xml字符串中的所有節點名稱,節點值和屬性。我做了這個:Java,用於讀取所有節點名稱,節點值和屬性的XPath表達式

private List<String> listOne = new ArrayList<String>(); 
private List<String> listTwo = new ArrayList<String>(); 

public void read(String xml) { 
    try { 
     // Turn String into a Document 
     Document document = DocumentBuilderFactory.newInstance() 
       .newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes())); 

     // Setup XPath to retrieve all tags and values 
     XPath xPath = XPathFactory.newInstance().newXPath(); 
     NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", document, XPathConstants.NODESET); 

     // Iterate through nodes 
     for(int i = 0; i < nodeList.getLength(); i++) { 
      Node node = nodeList.item(i); 
      listOne.add(node.getNodeName()); 
      listTwo.add(node.getNodeValue()); 
      // Another list to hold attributes 
     } 

    } catch(Exception e) { 
     LogHandle.info(e.getMessage()); 
    } 
} 

我在網上找到了表達式//text()[normalize-space()=''];但是,它不起作用。當我嘗試從listOne獲取節點名稱時,它只是#text。我試過//,但那也行不通。如果我有這個XML:

<Data xmlns="Somenamespace.nsc"> 
    <Test>blah</Test> 
    <Foo>bar</Foo> 
    <Date id="2">12242016</Date> 
    <Phone> 
     <Home>5555555555</Home> 
     <Mobile>5555556789</Mobile> 
    </Phone> 
</Data> 

listOne[0]應持有DatalistOne[1]應持有TestlistTwo[1]應持有blah,等等......所有屬性將被保存在另一個平行的列表中。

xPath應該評估什麼樣的表達?

注:XML字符串可以有不同的標籤,所以我不能硬編碼任何東西。

更新:嘗試這個循環:

NodeList nodeList = (NodeList) xPath.evaluate("//*", document, XPathConstants.NODESET); 

// Iterate through nodes 
for(int i = 0; i < nodeList.getLength(); i++) { 
    Node node = nodeList.item(i); 

    listOne.add(i, node.getNodeName()); 

    // If null then must be text node 
    if(node.getChildNodes() == null) 
     listTwo.add(i, node.getTextContent()); 
} 

但是,這僅獲得根元素Data,然後就停止。

+1

'text()'指元素內容。在您的示例XML中,'blah','bar'和'12242016'是文本節點。所以,'text()'可能不是你想要的。 – VGR

+0

謝謝!如果'text()'給出元素的內容,那麼'node()'會給節點? – syy

+1

我認爲可能需要一些澄清。在XML中,「節點」是指XML文檔中的每一個可能的信息,包括文本,註釋,處理指令等,而「元素」是指由開始標記和匹配結束標記組成的信息,或者單個自動關閉標籤('')。你真的想讀每個節點,或只是每個元素及其屬性? – VGR

回答

1

//*將選擇所有元素節點,//@*所有屬性節點。但是,元素節點在DOM中沒有有意義的節點值,因此您需要讀出getTextContent()而不是getNodeValue

你似乎考慮子元素的元素有一個「空」的價值,我認爲你需要檢查是否有子元素:

DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 
    docBuilderFactory.setNamespaceAware(true); 

    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 

    Document doc = docBuilder.parse("sampleInput1.xml"); 

    XPathFactory fact = XPathFactory.newInstance(); 
    XPath xpath = fact.newXPath(); 

    NodeList allElements = (NodeList)xpath.evaluate("//*", doc, XPathConstants.NODESET); 

    ArrayList<String> elementNames = new ArrayList<>(); 
    ArrayList<String> elementValues = new ArrayList<>(); 

    for (int i = 0; i < allElements.getLength(); i++) 
    { 
     Node currentElement = allElements.item(i); 
     elementNames.add(i, currentElement.getLocalName()); 
     elementValues.add(i, xpath.evaluate("*", currentElement, XPathConstants.NODE) != null ? null : currentElement.getTextContent()); 
    } 

    for (int i = 0; i < elementNames.size(); i++) 
    { 
     System.out.println("Name: " + elementNames.get(i) + "; value: " + (elementValues.get(i))); 
    } 

對於樣本輸入

<Data xmlns="Somenamespace.nsc"> 
    <Test>blah</Test> 
    <Foo>bar</Foo> 
    <Date id="2">12242016</Date> 
    <Phone> 
     <Home>5555555555</Home> 
     <Mobile>5555556789</Mobile> 
    </Phone> 
</Data> 

輸出爲

Name: Data; value: null 
Name: Test; value: blah 
Name: Foo; value: bar 
Name: Date; value: 12242016 
Name: Phone; value: null 
Name: Home; value: 5555555555 
Name: Mobile; value: 5555556789 
+0

我用'getTextContext()'完成了'// *'並且能夠獲取標籤名稱和值。但是,對於像'Data'這樣的父節點,它返回的文本內容就是它的子節點的所有內容。所以'listTwo.get(0)'返回'blah,bar,12242016'。我試着檢查'getChildNodes()'是否爲空,那麼不會獲得文本內容,但是循環剛剛停止。我如何做到這一點'listOne(0)'是'Data','listTwo(0)'是'null','listOne(1)'是'Test','listTwo(1)'是'blah'。我會更新OP。 – syy

+1

'getChildNodes'爲您提供'NodeList',從不'null'。甚至''有一個子節點,一個文本節點。你還想怎麼處理混合內容,如'

這是加粗文字。

'?你需要更仔細地解釋你想要的結果。 –

+0

哦,我明白了。關於你的例子,我不會有這樣的情況。它將嚴格像OP中顯示的那樣(更多地添加到XML示例中)。我只想'listOne'來保存所有元素和'listTwo'來保存與它們相關的文本。但是,如果一個元素包含子元素而沒有直接的文本,那麼對於該索引,listTwo應該爲null,如上述註釋中的示例所示。 – syy

相關問題