原生java解析xml的方法提供了兩個,DocumentBuilder 和 SAXParser.
試了第一個DOM方法,在解析輸出節點過程中,getNodeName()輸出節點名發現多出了幾個#text節點。
text.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- xml解析測試文件 -->
<LData>
<ldata>
<issue>123456</issue>
<date>20200115235900</date>
<nil></nil>
<nil2> </nil2>
<numbers>
<number>1</number>
<number>2</number>
<number>3</number>
<number>4</number>
<number>5</number>
<number>6</number>
</numbers>
</ldata>
<ldata>
<issue>222223</issue>
<date>2020-01-14 23:59:00</date>
<numbers>
<number>11</number>
</numbers>
</ldata>
</LData>
DOM.java
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
public class DOM {
//document解析器工廠
private static DocumentBuilderFactory docBuiFactory = null;
//document解析器可以通過documentBuiderFactory的newDocumentBuilder()函數獲取
private static DocumentBuilder docBuilder = null;
//document對象可以通過documentBuilder的newDocumentBuilder()函數獲取
private static Document doc = null;
//自定義對象book的集合用來存儲xml獲取的book對象
private static List<Book> books = null;
//靜態代碼塊用來初始化靜態屬性,只會在類的第一次加載執行一次
static {
try {
//初始化documentBuilderFactory
docBuiFactory = DocumentBuilderFactory.newInstance(); //newInstance通過反射機制創建DocumentBuilderFactory的實現類
//初始化documentBuilder
docBuilder = docBuiFactory.newDocumentBuilder(); //通過DocumentBuilderFactoryImpl的newDocumentBuilder()函數返回DocumentBuilder對象
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String filterBlankXMl(String xml) {
//校驗規則1位有一個空格就開始過濾,如果改為3則三個連續空格才過濾
Pattern p = Pattern.compile("\\s{1,}|\t|\r|\n");
Matcher m = p.matcher(xml);
xml = m.replaceAll("");
System.out.println("接受到的XML:\n" + xml);
return xml;
}
public static List<Book> getXml(String fileURL) throws Exception {
//將給定的url的內容解析為一個xml文檔,並返回document對象
doc = docBuilder.parse(fileURL);
//按順序獲取xml內所有book元素節點
NodeList IssueList = doc.getElementsByTagName("ldata");
books = new ArrayList<Book>();
//遍歷books
NodeList ldataList = doc.getElementsByTagName("ldata");//獲取所有的ldata節點
//遍歷所有的ldata節點
//for(int i = 0;i<ldataList.getLength();i++) {
Node numbersNode = ldataList.item(0);
//這里只取第一個ldata的節點數據
NodeList numberList = numbersNode.getChildNodes();
for(int j = 0;j<numberList.getLength();j++){
//if(!"#text".equals(numberList.item(j).getNodeName())){
System.out.println(numberList.item(j).getNodeName());
}
// }
return books;
}
public static void main(String[] args) {
String fileURL = "file:///XmlDemo/test.xml";
try {
List<Book> list = DOM.getXml(fileURL);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
發現
System.out.println(numberList.item(j).getNodeName());
輸出的結果:
#text
issue
#text
date
#text
number
#text
這個#text一度讓我很迷茫,從檢查xml是否寫錯到檢查讀取xmk的方法是否有問題,最后還是善用了搜索引擎😀。
原因主要是使用org.w3c.dom.Node的進行解析的,它會將你的回車也作為一個節點。在你的代碼中你打印.getLenth();得到的數值肯定比你寫的節點要多。
明白了這個原因就簡單多了,腦中出現了兩種方法。
1.想辦法把xml的回車空行去掉再解析.
既不用改動文件,也不會使getlength()的長度發生變化
正則匹配xml空格換行然后替換:
public static String filterBlankXMl(String xml) {
//校驗規則1位有一個空格就開始過濾,如果改為3則三個連續空格才過濾
Pattern p = Pattern.compile("\\s{1,}|\t|\r|\n");
Matcher m = p.matcher(xml);
xml = m.replaceAll("");
System.out.println("接受到的XML:\n" + xml);
return xml;
}
public static String readFileByLines(String fileName) {
File file = new File(fileName);
BufferedReader reader = null;
String content = "";
try {
// System.out.println("以行為單位讀取文件內容,一次讀一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
// 一次讀入一行,直到讀入null為文件結束
while ((tempString = reader.readLine()) != null) {
// 顯示行號
// System.out.println("line " + line + ": " + tempString);
content = content + tempString;
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return content;
}
String file = filterBlankXMl(readFileByLines(filepath));
//將格式化后的xml String 轉換成 InputStream 用parse解析
doc = docBuilder.parse(new ByteArrayInputStream(file.getBytes()));
2.輸出節點時判斷NodeName為#text則不進行處理否輸出.
雖然輸出正確,到getlength的長度還是變了
for ...{
if(!"#text".equals(numberList.item(j).getNodeName())){
//處理過濾的節點
System.out.println(numberList.item(j).getNodeName());
}
}
當然還可以使用dom4j等其他第三方jar