2013-04-26 69 views
2

解析XML文檔時遇到了一些麻煩。出於某種原因,有文本節點,我不希望他們是,因此我的測試變成紅色。該XML文件是這樣的:在Java中解析XML的問題

<?xml version="1.0" encoding="UTF-8"?> 
<RootNode> 
    <PR1>PR1</PR1> 
    <ROL>one</ROL> 
    <ROL>two</ROL> 
    <DG1>DG1</DG1> 
    <ROL>three</ROL> 
    <ZBK>ZBK</ZBK> 
    <ROL>four</ROL> 
</RootNode> 

現在我有此代碼段可以重現錯誤:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse(TestHL7Helper.class.getResourceAsStream("TestHL7HelperInput.xml")); 
Node root = doc.getFirstChild(); 
Node pr1 = root.getFirstChild(); 

檢查根可變產量[RootNode: null]這似乎是正確的,但後來不知何故全錯了。 pr1變量原來是一個文本節點[#text:\n ] - 但爲什麼解析器認爲新行和空格是文本節點?這不應該被忽略嗎?我試圖改變編碼,但也沒有幫助。有關於此的任何想法?

如果我刪除所有的新線條和空間,並有我的XML文檔中只有一行這一切工作正常...

+0

這裏是一個[DOM分析樣品] [1] 也許這會幫助你。 [1]:http://stackoverflow.com/a/7902162/529543 – 2013-04-26 08:21:10

+0

也許問題標題應該改變。我仔細研究了一下關於混合內容和DOM解析的一些信息,並在那裏得到了答案,但問題標題乍一看並沒有吸引我。就像「使用Java DOM解析帶有混合內容的XML的問題」。 – dodecaplex 2016-10-25 06:52:34

回答

0

您可以通過檢查節點的類型解決這一普遍問題:

if (someNode instanceof Element) { 
    // ... 
} 

這可以容易地形成一個環的一部分,如:

NodeList childNodes = root.getChildNodes(); 
for (int i = 0; i < childNodes.getLength(); i++) { 
    if (childNodes.item(i).getNodeType() == Node.ELEMENT) { 
    Element childElement = (Element) childNodes.item(i); 
    // ... 
    } 
} 

可替代地,使用類似XMLBeans以減少引入的錯誤時的人的可能性ually解析XML。獲得一個經過充分測試的圖書館來爲您完成這項工作!

+0

這是我想過的解決方案,但它有點難看。必須有一些東西不會用我所有的if和else來填充我的代碼,只是爲了檢查解析是否有問題。 – Viciouss 2013-04-26 08:24:00

+0

@Viciouss [Sirko的解決方案](http://stackoverflow.com/a/16231783/474189)更直接,如果你有獨特的名字。或者,您可以考慮使用類似[XMLBeans](http://xmlbeans.apache.org/documentation/tutorial_getstarted.html)的類來生成專門用於讀取與XSD/DTD匹配的XML文件的類。 – 2013-04-26 08:28:13

+0

我同意@Duncan - 使用現有的庫來處理您的解析。我過去使用過JDOM,並且發現它簡單直觀,沒有太多的學習曲線 – DaveH 2013-04-26 08:35:21

2

實際上,其他節點之間的所有文本本身形成一個文本節點。因此,如果您使用getFirstChild(),您還將檢索這些文本節點。

在你的情況下,所有的非文本子節點有一個獨特的名字,所以你可以通過使用getElementsByTagName()單獨讓他們:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse(TestHL7Helper.class.getResourceAsStream("TestHL7HelperInput.xml")); 
Node root = doc.getFirstChild(); 
Node pr1 = (root.getElementsByTagName("PR1"))[0]; 

一般來說,我不會依賴XML文檔中的位置,但在標籤名稱,屬性或ID等東西。

+0

我需要依靠這個,因爲我必須在其中一個測試中檢查兄弟姐妹。例如,我用getElementsByTagName獲取PR1節點,然後我想檢查有多少ROL節點落後。對於這個任務,我需要使用getNextSibling(),它似乎有完全相同的問題。 – Viciouss 2013-04-26 08:27:43

+0

@Viciouss也許這個問題將幫助你然後:http://stackoverflow.com/q/978810/1169798 – Sirko 2013-04-26 08:31:49

+0

我想我會做的只是相反的方式。我將使用xpath來選擇與特定名稱匹配的兄弟。其他方法似乎並不令人滿意。 – Viciouss 2013-04-26 08:40:40

2

XML支持混合內容,意思是元素可以同時具有文本元素和元素子節點。這是爲了支持使用情況如下所示:

<text>I've bolded the <b>important</b> part.</text> 

的input.xml

這意味着,在默認情況下DOM解析器將把空白節點下面的文檔作爲顯著的(下面是一個簡化XML文檔的版本):

<RootNode> 
    <PR1>PR1</PR1> 
</RootNode> 

演示代碼

如果您有XML架構,則可以在DocumentBuilderFactory上設置ignoringElementContentWhitespace屬性,因爲那樣DOM解析器將知道空白是否以及何時有意義。

import java.io.File; 
import javax.xml.XMLConstants; 
import javax.xml.parsers.*; 
import javax.xml.validation.*; 

import org.w3c.dom.Document; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
     Schema s = sf.newSchema(new File("src/forum16231687/schema.xsd")); 

     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     dbf.setSchema(s); 
     dbf.setIgnoringElementContentWhitespace(true); 

     DocumentBuilder db = dbf.newDocumentBuilder(); 
     Document d = db.parse(new File("src/forum16231687/input.xml")); 
     System.out.println(d.getDocumentElement().getChildNodes().getLength()); 
    } 

} 

模式。xsd

如果您創建schema.xsd,如下所示,那麼演示代碼將報告根元素有1個子節點。

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema"> 
    <element name="RootNode"> 
     <complexType> 
      <sequence> 
       <element name="PR1" type="string"/> 
      </sequence> 
     </complexType> 
    </element> 
</schema> 

如果更改schema.xsd使得RootNode具有混合內容的演示代碼將報告RootNode有3個節點。

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema"> 
    <element name="RootNode"> 
     <complexType mixed="true"> 
      <sequence> 
       <element name="PR1" type="string"/> 
      </sequence> 
     </complexType> 
    </element> 
</schema>