使用 Java 解析XML檔案
當您編寫應用程式時,您通常希望使用者自定義他們與應用程式的互動方式以及應用程式與系統的互動方式。這種方法通常稱為“首選項”或“設定”,它們儲存在“首選項檔案”或“配置檔案”中,有時簡稱為“配置配置”。配置檔案可以有多種格式,包括INI、JSON、YAML和XML。每種程式語言都以不同的方式解析這些格式。本文主要討論在用Java程式語言編寫軟體時,如何實現持久化配置。
選擇一種格式。
編寫配置檔案相當複雜。我嘗試過將配置項儲存在用逗號分隔的文字檔案中,也嘗試過將配置項儲存在非常詳細的YAML和XML中。對於配置檔案來說,最重要的是一致性和規律性。它們使您能夠簡單快速地編寫程式碼並從配置檔案中解析資料。同時,當使用者決定進行更改時,可以方便地儲存和更新配置。
目前有幾種流行的配置檔案格式。對於大多數常見的配置檔案格式,Java都有相應的庫。在本文中,我將使用XML格式。對於某些專案,您可能會選擇使用XML,因為它的突出特點是可以為所包含的資料提供大量的相關後設資料,而對於其他專案,您可能會因為其冗長性而不選擇XML。在Java中使用XML非常容易,因為預設情況下它包含許多健壯的XML庫。
<p>
XML基礎
</p>
<p>
對XML的討論是一個大話題。我有一本關於XML的書,有700多頁。幸運的是,使用XML不需要了解太多它的特性。就像HTML一樣,XML是一種帶有開始和結束標籤的分層標記語言,每個標籤(tag)可以包含零個或多個資料。下面是一個簡單的XML示例片段:
企鵝 在這個自我描述的示例中,XML解析器使用了以下概念:
文件:標籤標記文件的開始,標籤標記文件的結束。
節點:標籤代表一個節點。
元素:企鵝,從頭到尾,代表一種元素。
內容:在元素中,字串企鵝就是內容。
信不信由你,只要你知道了上面的概念,你就可以開始編寫和解析XML檔案了。
建立一個示例配置檔案。
要學習如何解析XML檔案,只需要一個最小的樣本檔案就足夠了。現在假設有一個配置檔案,它儲存了圖形介面視窗的屬性:
黑暗0Tango
建立一個名為~/的目錄。config/DemoXMLParser:
$ mkdir ~/。config/DemoXMLParser
使用 Java 解析 XML
如果你是 Java 的初學者,你可以先閱讀我寫的
。一旦你對 Java 比較熟悉了,開啟你最喜愛的整合開發工具(IDE),建立一個新工程。我會把我的新工程命名為
myConfigParser
。
剛開始先不要太關注依賴匯入和異常捕獲這些,你可以先嚐試用
javax
和
java.io
包裡的標準 Java 擴充套件來例項化一個解析器。如果你使用了 IDE,它會提示你匯入合適的依賴。如果沒有,你也可以在文章稍後的部分找到完整的程式碼,裡面就有完整的依賴列表。
Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser");File configFile = new File(configPath.toString(), "myconfig.xml");DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = null;builder = factory.newDocumentBuilder();Document doc = null;doc = builder.parse(configFile);doc.getDocumentElement().normalize();
這段示例程式碼使用了
java.nio.Paths
類來找到使用者的主目錄,然後在拼接上預設配置檔案的路徑。接著,它用
java.io.File
類來把配置檔案定義為一個
File
物件。
緊接著,它使用了
javax.xml.parsers.DocumentBuilder
和
javax.xml.parsers.DocumentBuilderFactory
這兩個類來建立一個內部的文件構造器,這樣 Java 程式就可以匯入並解析 XML 資料了。
最後,Java 建立一個叫
doc
的文件物件,並且把
configFile
檔案載入到這個物件裡。透過使用
org.w3c.dom
包,它讀取並規範化了 XML 資料。
基本上就是這樣啦。理論上來講,你已經完成了資料解析的工作。可是,如果你不能夠訪問資料的話,資料解析也沒有多少用處嘛。所以,就讓我們再來寫一些查詢,從你的配置中讀取重要的屬性值吧。
使用 Java 訪問 XML 的值
從你已經讀取的 XML 文件中獲取資料,其實就是要先找到一個特定的節點,然後遍歷它包含的所有元素。通常我們會使用多個迴圈語句來遍歷節點中的元素,但是為了保持程式碼可讀性,我會盡可能少地使用迴圈語句:
NodeList nodes = doc.getElementsByTagName("window");for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); }}
這段示例程式碼使用了
org.w3c.dom.NodeList
類,建立了一個名為
nodes
的
NodeList
物件。這個物件包含了所有名字匹配字串
window
的子節點,實際上這樣的節點只有一個,因為本文的示例配置檔案中只配置了一個。
緊接著,它使用了一個
for
迴圈來遍歷
nodes
列表。具體過程是:根據節點出現的順序逐個取出,然後交給一個
if-then
子句處理。這個
if-then
子句建立了一個名為
myelement
的
Element
物件,其中包含了當前節點下的所有元素。你可以使用例如
getChildNodes
和
getElementById
方法來查詢這些元素,專案中還
記錄了 其他查詢方法。
在這個示例中,每個元素就是配置的鍵。而配置的值儲存在元素的內容中,你可以使用
.getTextContent
方法來提取出配置的值。
在你的 IDE 中執行程式碼(或者執行編譯後的二進位制檔案):
$ java ./DemoXMLParser.javaProperty = windowTheme = DarkFullscreen = 0Icon set = Tango
下面是完整的程式碼示例:
package myConfigParser;import java.io.File;import java.io.IOException;import java.nio.file.Path;import java.nio.file.Paths;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public class ConfigParser { public static void main(String[] args) { Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); } Document doc = null; try { doc = builder.parse(configFile); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } doc.getDocumentElement().normalize(); NodeList nodes = doc.getElementsByTagName("window"); for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); } // close if } // close for } // close method} //close class
使用 Java 更新 XML
使用者時不時地會改變某個偏好項,這時候
org.w3c.dom
庫就可以幫助你更新某個 XML 元素的內容。你只需要選擇這個 XML 元素,就像你讀取它時那樣。不過,此時你不再使用
.getTextContent
方法,而是使用
.setTextContent
方法。
updatePref = myelement.getElementsByTagName("fullscreen").item(0);updatePref.setTextContent("1");System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());
這麼做會改變應用程式記憶體中的 XML 文件,但是還沒有把資料寫回到磁碟上。配合使用
javax
和
w3c
庫,你就可以把讀取到的 XML 內容寫回到配置檔案中。
TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer xtransform;xtransform = transformerFactory.newTransformer();DOMSource mydom = new DOMSource(doc);StreamResult streamResult = new StreamResult(configFile);xtransform.transform(mydom, streamResult);
這麼做會沒有警告地寫入轉換後的資料,並覆蓋掉之前的配置。
下面是完整的程式碼,包括更新 XML 的操作:
package myConfigParser;import java.io.File;import java.io.IOException;import java.nio.file.Path;import java.nio.file.Paths;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerException;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public class ConfigParser { public static void main(String[] args) { Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } Document doc = null; try { doc = builder.parse(configFile); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } doc.getDocumentElement().normalize(); Node updatePref = null;// NodeList nodes = doc.getChildNodes(); NodeList nodes = doc.getElementsByTagName("window"); for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); updatePref = myelement.getElementsByTagName("fullscreen").item(0); updatePref.setTextContent("2"); System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); } // close if }// close for // write DOM back to the file TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer xtransform; DOMSource mydom = new DOMSource(doc); StreamResult streamResult = new StreamResult(configFile); try { xtransform = transformerFactory.newTransformer(); xtransform.transform(mydom, streamResult); } catch (TransformerException e) { e.printStackTrace(); } } // close method} //close class
如何保證配置不出問題
編寫配置檔案看上去是一個還挺簡單的任務。一開始,你可能會用一個簡單的文字格式,因為你的應用程式只要寥寥幾個配置項而已。但是,隨著你引入了更多的配置項,讀取或者寫入錯誤的資料可能會給你的應用程式帶來意料之外的錯誤。一種幫助你保持配置過程安全、不出錯的方法,就是使用類似 XML 的規範格式,然後依靠你用的程式語言的內建功能來處理這些複雜的事情。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69979876/viewspace-2886073/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- python XML 檔案解析PythonXML
- jdom解析xml檔案XML
- 如何使用 ABAP 程式碼解析 XML 檔案XML
- XML 檔案解析實踐 (DOM 解析)XML
- Python解析XML檔案生成HTMLPythonXMLHTML
- java 語音用xml檔案實現圖形介面 xml檔案JavaXML
- Java系列:讀取XML檔案JavaXML
- Java解析XMLJavaXML
- springMVC---配置檔案解析(web.xml)SpringMVCWebXML
- 基於 DOM 的 XML 檔案解析類XML
- c#(解析xml檔案基礎方法)C#XML
- mybatis原始碼配置檔案解析之五:解析mappers標籤(解析XML對映檔案)MyBatis原始碼APPXML
- 使用xml檔案配置SSM整合XMLSSM
- java class檔案解析Java
- xml檔案XML
- java去除xml檔案中的標籤JavaXML
- 使用C#讀寫xml檔案C#XML
- mybatis的全域性配置檔案SqlMapConfig.xml解析MyBatisSQLXML
- 元件使用總結:使用 JAXB 實現 XML檔案和java物件互轉元件XMLJava物件
- java解析yaml配置檔案JavaYAML
- java class 檔案格式解析Java
- java使用jaxb解析XML(含根據xml自動生成實體類)JavaXML
- Java解析xml檔案遇到特殊符號&會出現異常的解決方案JavaXML符號
- ie中jQuery無法解析xml檔案的解決方案jQueryXML
- AndroidMainfest.xml檔案AndroidAIXML
- xml是什麼格式的檔案 xml檔案怎麼開啟XML
- 解析XML檔案時,無效的XML 字元 (Unicode: 0x7)異常處理XML字元Unicode
- 使用DocumentBuilderFactory解析XML淺談UIXML
- Android學習筆記之AndroidManifest.xml檔案解析(詳解)Android筆記XML
- 死磕Spring之IoC篇 - 解析自定義標籤(XML 檔案)SpringXML
- 死磕Spring之IoC篇 - BeanDefinition 的解析階段(XML 檔案)SpringBeanXML
- Go xml檔案處理GoXML
- 使用GeoTools解析shp檔案內容
- nodejs xmlreader 讀寫xml檔案NodeJSXML
- C#讀取Xml檔案C#XML
- ajax與XML檔案互動XML
- 給XML檔案定義DTDXML
- 清單檔案 AndroidManifest.xmlAndroidXML