http://www.cnblogs.com/hoojo/archive/2011/08/11/2134638.html 可擴展標記語言——eXtensible Markup Language 用戶可以自己定義語言標記,只要有開始和閉合標簽即可。 xsl裝飾、修飾xml的顯示結果。 dtd約束xml ...
http://www.cnblogs.com/hoojo/archive/2011/08/11/2134638.html
可擴展標記語言——eXtensible Markup Language
用戶可以自己定義語言標記,只要有開始和閉合標簽即可。
xsl裝飾、修飾xml的顯示結果。
dtd約束xml文件中的標記。
Ø XML的優點:
1、xml可以讓數據和標記分離。
2、異質信息互通
3、機器語言
4、用交流語言替代html裝飾語言
5、簡單易用
6、可以自定義、可擴展
Ø XML和HTML比較
比較內容 |
HTML |
XML |
可擴展性 |
不具有擴展性、標記固定 |
是元標記語言,可以定義新標記,用戶可以自定義標記 |
側重點 |
側重於信息的表現形式為什麼格式被關註 |
側重於結構化的描述信息,數據是什麼為XML所關註 |
語法 |
不嚴格(嵌套、配對) |
嚴格嵌套、配對,並按照DTD要求輸出 |
可讀性、可維護性 |
難於閱讀和維護 |
結構清晰,便於閱讀維護 |
數據本身、顯示 |
數據和顯示合為一處 |
數據與顯示分離 |
重用性 |
低 |
可重用性高 |
Ø JDOM操作XML
JDOM可以很方便的操作XML文檔,完成XML內容的創建、修改,已經遍歷Document文檔中的XML元素,完成查詢等。下麵我們就用JDOM完成這些功能。
# 準備
首先我們要準備jdom相關的jar包
jdom-jar下載地址:http://www.jdom.org/dist/binary/
jaxen在jdom的zip壓縮包中可以找到。
Junit是測試用的,可以不添加。但需要用main方法測試。
其次,是準備測試工作。部分測試代碼:
package com.hoo.test;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.Text;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* <b>function:</b> JDOM操作XML
* @author hoojo
* @createDate 2011-8-4 下午12:34:09
* @file DocumentTest.java
* @package com.hoo.test
* @project JDOMTest
* @blog http://blog.csdn.net/IBM_hoojo
* @email [email protected]
* @version 1.0
*/
public class DocumentTest {
private XMLOutputter out = null;
@Before
public void init() {
//輸出文件信息
out = new XMLOutputter();
}
@After
public void destory() {
if (out != null) {
out = null;
}
System.gc();
}
/**
* <b>function:</b>輸出Document文檔信息
* @author hoojo
* @createDate 2011-8-5 下午12:10:27
* @param doc
*/
private void print(Document doc) {
//設置XML文件編碼格式
//out.setFormat(Format.getCompactFormat().setEncoding("gb2132"));
System.out.println(out.outputString(doc));
}
private void fail(Object o) {
if (o != null) {
System.out.println(o);
}
}
}
# 創建Document
/**
* 創建xml元素
*/
@Test
public void createDoc() {
Document doc = null;
//method 1、創建一個Doc文檔,添加一個元素root
doc = new Document(new Element("root"));
print(doc);
//method 2、創建一個Doc文檔,添加一個元素root,設置root元素的節點文本
doc = new Document(new Element("root").setText("this is a root el"));
print(doc);
//method 3、創建一個Doc文檔,添加一個元素root,設置root元素的節點文本且添加一個屬性id,值為110
Element root = new Element("root");
root.setText("this is a root el");
root.setAttribute("id", "110");
doc.setRootElement(root);
fail("method 3: \n" + out.outputString(doc));
//method 4、創建一個Doc文檔,添加一個元素root,設置root元素的節點文本
doc = new Document();
doc.addContent(new Element("root").setText("this is a root el"));
fail("method 4: \n" + out.outputString(doc));
fail(doc.toString());
}
* new Document可以創建一個doc文檔
當給Document傳遞一個Element參數時,這個Element就是根元素;
當調用Document的setRootElement方法時,可以設置當前Doc的根元素;
當調用doc的addContent的時候,添加的元素將會是根元素;
doc = new Document(new Element("root").setText("this is a root el"));
上面就創建了一個doc,根元素是root,root節點的內容是this is a root el;
註意setText方法返回的對象是當前Element,類似是StringBuffer的append方法;
* new Element()可以創建一個元素
如果傳遞參數那麼這個參數將會是元素節點的名稱;
Element的setText方法可以設置元素的文本值;
Element root = new Element("root");
root.setText("this is a root el");
創建一個節點名稱為root的元素,文本是this is a root el
* setAttribute()可以設置某個具體節點的屬性值
root.setAttribute("id", "110");
給root節點添加一個id,值為110
* addContent添加註釋
root .addContent(new Comment("註釋"));
在root元素下添加一個註釋;
addContent是向元素中添加內容,而setContent是設置內容;
* setText設置元素文本內容
root.setText("this is a root el");
同樣
root. setContent(new Text("this is text"))
同樣
root.addContent("this is text");
下麵用上面的這些方法,創建一篇XML文檔。文檔內容如下:
/**
創建一遍xml文檔
<?xml version="1.0" encoding="UTF-8"?>
<car vin="123fhg5869705iop90">
<!--Description of a car-->
<make>Toyota</make>
<model>Celica</model>
<year>1997</year>
<color>green</color>
<license state="CA">1ABC234</license>
</car>
*/
@Test
public void createXMLDoc() {
//創建一個car的元素
Element carEl = new Element("car");
//創建vin屬性,並設置值
carEl.setAttribute("vin", "123fhg5869705iop90");
//創建註釋
carEl.addContent(new Comment("Description of a car"));
//創建一個make元素,設置文本內容
carEl.addContent(new Element("make").setText("Toyota"));
//創建一個model元素,添加一個文本元素
carEl.addContent(new Element("model").setContent(new Text("Celica")));
//創建一個year元素,添加文本內容
carEl.addContent(new Element("year").addContent("1997"));
//創建一個color元素,文本內容是green
carEl.addContent(new Element("color").setText("green"));
//創建一個license的元素
Element licenseEl = new Element("license");
//為license元素添加文本內容
licenseEl.addContent("1ABC234");
//創建一個state的屬性,值為CA
licenseEl.setAttribute("state", "CA");
//將licenseEl添加到根元素中
carEl.addContent(licenseEl);
//將car元素設置為根元素
Document doc = new Document(carEl);
print(doc);
/*out = new XMLOutputter();
try {
out.output(doc, System.out);
} catch (IOException e) {
e.printStackTrace();
}*/
}
方法運行後,所創建的文檔和上面註釋文檔內容相同
# 讀取XML文件的內容
disk.xml文件內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<HD>
<disk name="C">
<capacity>8G</capacity>
<directories>200</directories>
<files>1580</files>
</disk>
<disk name="D">
<capacity>10G</capacity>
<directories>500</directories>
<files>3000</files>
</disk>
<disk2 name="E">
<capacity>11G</capacity>
<directories>50</directories>
<files size="200" modifyDate="2011-08-3">
<file>Java book</file>
<file>Spring.txt</file>
<file>strtus.doc</file>
</files>
</disk2>
<files size="220">500</files>
</HD>
讀取disk文件的內容,代碼如下:
/**
* <b>function:</b>讀取xml文件中的元素
* @author hoojo
* @createDate 2011-8-4 下午04:54:17
*/
@Test
@SuppressWarnings("unchecked")
public void readXMLContent() {
SAXBuilder builder = new SAXBuilder();
try {
Document doc = builder.build(new File("file/disk.xml"));
Element rootEl = doc.getRootElement();
//獲得所有子元素
List<Element> list = rootEl.getChildren();
//List<Element> list = rootEl.getChildren("disk");
for (Element el : list) {
//獲取name屬性值
String name = el.getAttributeValue("name");
//獲取子元素capacity文本值
String capacity = el.getChildText("capacity");
//獲取子元素directories文本值
String directories = el.getChildText("directories");
String files = el.getChildText("files");
System.out.println("磁碟信息:");
System.out.println("分區盤符:" + name);
System.out.println("分區容量:" + capacity);
System.out.println("目錄數:" + directories);
System.out.println("文件數:" + files);
System.out.println("-----------------------------------");
}
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
* getChildren方法可以獲取所有子元素
* getChildren(elName)可以獲取所有名稱為elName的子節點
* getAttributeValue可以獲取指定屬性的值
* getChildText可以獲取子節點的文本值
# 遞歸顯示文檔信息
/**
* 遞歸返回指定格式的“--”
*/
private String format(int i) {
String temp = "";
if (i > 0) {
temp += "--";
i--;
temp += format(i);
}
return temp;
}
/**
* <b>function:</b>顯示當前節點所有Element的屬性信息
* @author hoojo
* @createDate 2011-8-4 下午06:10:53
* @param el
* @return
*/
@SuppressWarnings("unchecked")
private String getAttrInfo(Element el) {
List<Attribute> attrs = el.getAttributes();
return getAttrInfo(attrs);
}
/**
* <b>function:</b>顯示屬性信息
* @author hoojo
* @createDate 2011-8-9 下午03:52:59
* @param attrs
* @return
*/
private String getAttrInfo(List<Attribute> attrs) {
StringBuilder info = new StringBuilder();
for (Attribute attr : attrs) {
info.append(attr.getName()).append("=").append(attr.getValue()).append(", ");
}
if (info.length() > 0) {
return "[" + info.substring(0, info.length() - 2)+ "]";
}
return "";
}
/**
* <b>function:</b>遞歸顯示文檔節點元素信息
* @author hoojo
* @createDate 2011-8-4 下午05:56:34
* @param i
* @param list
*/
@SuppressWarnings("unchecked")
private void print(int i, List<Element> list) {
i++;
for (Element el : list) {
List<Element> childs = el.getChildren();
if (childs.size() > 0) {
fail(format(i) + el.getName() + " " + getAttrInfo(el));
print(i, childs);
} else {
fail(format(i) + el.getName() + ":" + el.getText() + " " + getAttrInfo(el));
}
}
}
調用print(0, root.getChildren());方法就可以看到一篇格式化後輸出的文檔內容
#############顯示文檔信息###############
--HD
----disk [name=C]
------capacity:8G
------directories:200
------files:1580
----disk [name=D]
------capacity:10G
------directories:500
------files:3000
----disk2 [name=E]
------capacity:11G
------directories:50
------files [size=200, modifyDate=2011-08-3]
--------file:Java book
--------file:Spring.txt
--------file:strtus.doc
----files:500 [size=220]
# XPath查詢遍歷XML文檔
/**
* <b>function:</b>用xpath遍歷xml信息
* @author hoojo
* @createDate 2011-8-4 下午04:56:52
* xpath參考:http://www.w3school.com.cn/xpath/xpath_functions.asp
*
* nodeName 選取此節點的所有子節點
/ 從根節點選取
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的
. 選取當前節點
.. 選取當前節點的父節點
@ 選取屬性
* 匹配任何元素節點
@* 匹配任何屬性節點
node() 配任何類型的節點
ancestor 選取當前節點的所有先輩(父、祖父等)
ancestor-or-self 選取當前節點的所有先輩(父、祖父等)以及當前節點本身
attribute 選取當前節點的所有屬性
child 選取當前節點的所有子元素。
descendant 選取當前節點的所有後代元素(子、孫等)。
descendant-or-self 選取當前節點的所有後代元素(子、孫等)以及當前節點本身。
following 選取文檔中當前節點的結束標簽之後的所有節點。
namespace 選取當前節點的所有命名空間節點
parent 選取當前節點的父節點。
preceding 選取文檔中當前節點的開始標簽之前的所有節點。
preceding-sibling 選取當前節點之前的所有同級節點。
self 選取當前節點。
child::book 選取所有屬於當前節點的子元素的 book 節點
attribute::languane 選取當前節點的 languange 屬性
child::* 選取當前節點的所有子元素
attribute::* 選取當前節點的所有屬性
child::text() 選取當前節點的所有文本子節點
child::node() 選取當前節點的所有子節點
descendant::book 選取當前節點的所有 book 後代
ancestor::book 選擇當前節點的所有 book 先輩
*/
@SuppressWarnings("unchecked")
@Test
public void queryElementByXPath() {
SAXBuilder builder = new SAXBuilder();
try {
Document doc = builder.build(new File("file/disk.xml"));
List<Element> list = XPath.selectNodes(doc, "/HD/disk");
for (Element el : list) {
String name = el.getAttributeValue("name");
String capacity = el.getChildText("capacity");
String directories = el.getChildText("directories");
String files = el.getChildText("files");
System.out.println("磁碟信息:");
System.out.println("分區盤符:" + name);
System.out.println("分區容量:" + capacity);
System.out.println("目錄數:" + directories);
System.out.print("文件數:" + files);
String capacityText = ((Text) XPath.selectSingleNode(el, "//disk[@name='" + name + "']/capacity/text()")).getTextNormalize();
System.out.println("#" + capacityText);
System.out.println("-----------------------------------");
}
//顯示文檔信息
System.out.println("#############顯示文檔信息###############");
print(0, doc.getContent());
//獲得hd元素
System.out.println("#############顯示HD子元素信息###############");
Element root = (Element) XPath.selectSingleNode(doc, "/HD");
//fail(root.getChildren().size());
print(0, root.getChildren());
//獲取hd下所有元素
System.out.println("#############顯示HD子元素信息###############");
List roots = (List) XPath.selectNodes(doc, "/HD/*");
//fail(roots.size());
print(0, roots);
//獲得hd下的所有disk元素
System.out.println("#############顯示disk信息###############");
roots = (List) XPath.selectNodes(doc, "/HD/disk");
//fail(roots.size());
print(0, roots);
System.out.println("#############顯示disk2信息###############");
roots = (List) XPath.selectNodes(doc, "/HD/disk2");
print(0, roots);
System.out.println("#############顯示任意路徑下的files信息###############");
roots = (List) XPath.selectNodes(doc, "//files");
print(0, roots);
System.out.println("#############顯示任意路徑下的files指定下標的file信息###############");
roots = (List) XPath.selectNodes(doc, "//files/file[1]");
print(0, roots);
System.out.println("#############顯示任意路徑下的files最後的file信息###############");
roots = (List) XPath.selectNodes(doc, "//files/file[last()]");
print(0, roots);
System.out.println("#############顯示任意路徑下的files倒數第二的file信息###############");
roots = (List) XPath.selectNodes(doc, "//files/file[last() - 1]");
print(0, roots);
System.out.println("#############顯示任意路徑下的files的子元素file位置position在第二的file信息###############");
roots = (List) XPath.selectNodes(doc, "//files/file[position() = 2]");
//roots = (List) XPath.selectNodes(doc, "//files/file[position() > 2]");
print(0, roots);
System.out.println("#############顯示任意路徑下的files第三個file的當前節點的前面所有同級節點信息###############");
roots = (List) XPath.selectNodes(doc, "//files/file[3]/preceding-sibling::*");
print(0, roots);
System.out.println("#############顯示任意路徑下的disk2之前的所有節點信息###############");
roots = (List) XPath.selectNodes(doc, "//disk2/preceding::*");
print(0, roots);
System.out.println("#############顯示任意路徑下的disk2之後的所有節點信息###############");
roots = (List) XPath.selectNodes(doc, "//disk2/following::*");
print(0, roots);
System.out.println("#############顯示任意路徑下的files的所有屬性信息###############");
roots = (List) XPath.selectNodes(doc, "//files/attribute::*");
fail(getAttrInfo(roots));
System.out.println("#############顯示任意路徑下的節點是disk屬性name=C的信息###############");
roots = (List) XPath.selectNodes(doc, "//disk[@name='C']");
print(0, roots);
System.out.println("#############顯示任意路徑下的節點是disk的子元素的文本中含義5和8節點的信息###############");
roots = (List) XPath.selectNodes(doc, "//disk/child::*[contains(text(), '8') and contains(text(), '5')]");
//roots = (List) XPath.selectNodes(doc, "//disk/child::*[contains(text(), '8') or contains(text(), '5')]");
print(0, roots);
System.out.println("#############顯示任意路徑下的節點是files且有屬性size的信息###############");
roots = (List) XPath.selectNodes(doc, "//files[@size]");
print(0, roots);
System.out.println("#############顯示HD節點下capacity的值為11G的信息###############");
//roots = (List) XPath.selectNodes(doc, "/HD/disk/capacity[text()='11G']");
roots = (List) XPath.selectNodes(doc, "/HD/*/capacity[text()='11G']");
//roots = (List) XPath.selectNodes(doc, "/*/*/capacity[text()='11G']");
print(0, roots);
//parent::*表示父節點集合
System.out.println("#############顯示任意路徑下的節點是files且屬性size有值的父節點的信息###############");
roots = (List) XPath.selectNodes(doc, "//files[@size='200']/parent::*");
print(0, roots);
System.out.println("#############顯示任意路徑下的節點disk的子節點的capacity信息###############");
roots = (List) XPath.selectNodes(doc, "//disk/child::capacity");
print(0, roots);
//獲取c盤的大小
System.out.println("獲取c盤的大小");
Text filesText = (Text) XPath.selectSingleNode(doc, "/HD/disk[@name='C']/files/text()");
System.out.println(filesText.getTextNormalize());
//XPath function
/**
string concat (string, string, string*) 聯接兩個字元串
boolean starts-with (string, string) 判斷某字元串是否以另一字元串開頭
boolean contains (string, string) 判斷某字元串是否包含另一字元串
string substring (string, number, number) 取子字元串
number string-length (string) 測字元串長度
number sum (node-set) 求和
number floor (number) 求小於此數的最大整數值
number ceiling (number) 求大於此數最小整數值
**/
System.out.println("獲取@size的和大於200的");
roots = (List) XPath.selectNodes(doc, "//files[sum(@size) > 200]");
print(0, roots);
System.out.println("查找directories的內容長度小於3的");
roots = (List) XPath.selectNodes(doc, "//directories[string-length(text()) < 3]");
print(0, roots);
System.out.println("查找files的內容包含5的");
roots = (List) XPath.selectNodes(doc, "//files[contains(text(), '5')]");
print(0, roots);
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
# 刪除元素及其他操作
/**
* <b>function:</b>列印doc相關信息
* @author hoojo
* @createDate 2011-8-10 下午06:29:01
*/
@SuppressWarnings("unchecked")
@Test
public void printInfo() {
SAXBuilder builder = new SAXBuilder();
try {
//builder.setFeature("user", true);
//builder.setIgnoringBoundaryWhitespace(true);
//忽略元素內容的空格
//builder.setIgnoringElementContentWhitespace(true);
Document doc = builder.build(new File("file/web.xml"));
fail("baseURI: " + doc.getBaseURI());
fail("ContentSize: " + doc.getContentSize());
//System.out.println("getContent: ");
//print(0, doc.getContent());
fail("getContent index: " + doc.getRootElement().getContent(1));
fail("getDocType: " + doc.getDocType());
fail("getParent: " + doc.getRootElement().getContent(1).getParent());
fail("getProperty: " + doc.getProperty("filter"));
print(0, XPath.selectNodes(doc, "//*[contains(text(), '#')]"));
fail("getText: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getText());
fail("getTextTrim: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getTextTrim());
fail("getTextNormalize: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getTextNormalize());
fail("hasRootElement: " + doc.hasRootElement());
//如果文檔帶有Namespace一定要設置Namespace,不然無法讀取內容
Namespace ns = Namespace.getNamespace("http://java.sun.com/xml/ns/javaee");
Element servletEl = doc.getRootElement().getChild("servlet", ns);
fail("servletEl: " + servletEl);
print(0, servletEl.getChildren());
fail("getChildText: " + servletEl.getChildText("servlet-class", ns));
fail("getChildTextNormalize: " + servletEl.getChildTextNormalize("servlet-name", ns));
fail("getChildTextTrim: " + servletEl.getChildTextTrim("servlet-class", ns));
fail("getName: " + servletEl.getName());
fail("getNamespacePrefix: " + servletEl.getNamespacePrefix());
fail("getNamespace: " + servletEl.getNamespace());
fail("getQualifiedName: " + servletEl.getQualifiedName());
Element classEl = servletEl.getChild("servlet-class", ns);
fail("getText: " + classEl.getText());
fail("getTextNormalize: " + classEl.getTextNormalize());
fail("getTextTrim: " + classEl.getTextTrim());
fail("getValue: " + classEl.getValue());
//刪除節點
fail(doc.getRootElement().removeContent(3));
//print(0, doc.removeContent());
//print(0, doc.getRootElement().getChildren());
fail(servletEl.removeChild("servlet-class", ns));
fail(servletEl.removeChildren("init-param", ns));
print(0, servletEl.getChildren());
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}