DOM解析处理流程:
DOM(Document Object Module)是W3C提供的一组XML的解析标准接口,由java扩展类实现的(org.w3c.dom),它将整个XML文件读取到内存中,形成一棵DOM树。
- 使用DOM读XML文件的代码流程
private static void readXML() throws Exception
{
File file = new File("F:" + File.separator + "book.xml");
InputStream inputStream = new FileInputStream(file);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
//NodeList bookList = document.getElementsByTagName("book"); //父节点
NodeList titleList = document.getElementsByTagName("title");
NodeList priceList = document.getElementsByTagName("price");
for (int i = 0; i < titleList.getLength(); i++)
{
Element title = (Element) titleList.item(i); //将Node强转为Element
Element price = (Element) priceList.item(i);
System.out.println("title = " + title.getTextContent() + " , price = " + price.getTextContent()); //获取文本节点内容
}
inputStream.close();
}
这样子的代码有个致命的缺点,就是可以跳过父节点,直接获取下面的子节点,父节点内的属性也将无法获取;
可以先获取父节点,在从父节点中调用getElementsByTagName(),获取该父节点的子元素。
NodeList bookList = document.getElementsByTagName("book")
for(int i = 0; i < bookList.getLength(); i++)
{
Element bookEle = (Element) bookList.item(i);
String id = bookEle.getAttribute("id");
String title=((Element)booEle.getElementsByTagName("title").item(0)).getFirstChild().getNodeValue(); //获得文本节点
String price=((Element)booEle.getElementsByTagName("price").item(0)).getFirstChild().getNodeValue();
}
通过这里我们可以发现,文本节点也是该父节点的FirstChild;
显然的是,如果使用这样的写法,我们想要获取文本内容,将变得极其繁杂,代码重用性太差!
- 使用DOM写XML文件的代码流程
private static void writeXML() throws Exception
{
File file = new File("F:" + File.separator + "book.xml");
OutputStream outputStream = new FileOutputStream(file);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document document = builder.newDocument(); //创建新的Document
Element booksEle = document.createElement("books"); //创建新的Element,位置未知
String titles[] = {"三体","带上她的眼睛","球状闪电"};
double prices[] = {33.33,10.1,22.22};
for (int i = 0; i < titles.length; i++)
{
Element bookEle = document.createElement("book");
Element titleEle = document.createElement("title");
Element priceEle = document.createElement("price");
titleEle.appendChild(document.createTextNode(titles[i])); //为该元素设置文本节点
priceEle.appendChild(document.createTextNode(String.valueOf(prices[i])));
bookEle.appendChild(titleEle); //为book元素设置子元素
bookEle.appendChild(priceEle);
booksEle.appendChild(bookEle);
}
document.appendChild(booksEle); //将父元素给document
/* 储存过程 */
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
Source source = new DOMSource(document); //设置文件源
Result result = new StreamResult(file); //设置目的文件
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //设置字符编码
transformer.transform(source,result); //进行写操作
}
使用DOM操作无论是在读还是写上面,都是一堆繁杂的代码
并且使用DOM进行增删改的时候,会有一些坑,比如每remove一个节点时,其NodeList的length会改变,for循环删除会带来难以理解的删除效果。
SAX解析处理流程
SAX(Simple API for XML)是一种民间产物,不属于W3C的开发标准,存在与很多语言之中,SAX只能进行XML的解析,不能进行XML的写操作。
在进行SAX解析的时候,应该继承并重写DefaultHandler类,该类在进行SAX顺序解析的时候,遇到关键点会回调自己所写的方法
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class BookSAX extends DefaultHandler
{
@Override
public void startDocument() throws SAXException
{
super.startDocument(); //在读Document开始时,进行的操作
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
super.startElement(uri, localName, qName, attributes); //在读到一个元素时,进行的操作
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
super.characters(ch, start, length); //在读到一个文本节点时,进行的操作
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
super.endElement(uri, localName, qName); //在读完一个元素时,进行的操作
}
@Override
public void endDocument() throws SAXException
{
super.endDocument(); //在读完Document时,进行的操作
}
}
主方法中
public static void main(String[] args) throws Exception
{
File file = new File("F:" + File.separator + "book.xml");
InputStream inputStream = new FileInputStream(file);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
saxParser.parse(inputStream, new BookSAX()); //使用已经定义好的SAX解析方式进行文件解析
}
SAX解析并不常用,我们学习,应该是学习它的设计思想;将XML读取到的数据,可以通过自己定义的SAX处理器转化为VO类对象。
DOM与SAX的区别
- DOM:属于W3C定义的XML文件的处理标准,本身可以实现数据的读写与修改功能,但是内存中需要形成DOM,如果XML文件太大,将占用大量的内存资源,并且DOM操作过程繁琐,所以不适合读取大型文件和繁杂的文件。
- SAX:属于民间标准,采用顺序的方式实现XML的读取,本身由于不会全部将数据加载到内存中,所以时候于较大的文件读取,但是缺点是SAX不允许修改文件,编写的SAX处理类也较为繁杂(程序中莫名多了一个类)。
DOM4J解析处理流程
DOM4J是非JDK自带的一个jar包,是常用的XML文件解析工具,综合了DOM和SAX的优点,也减少了大量的多余代码。个人认为缺点是,里面方法过于繁杂,经常用到的不多
- 使用DOM4J进行写操作
private static void createXML_2() throws Exception
{
int[] id_s = {10, 20, 30};
String[] titles = {"三国演义", "红楼梦", "水浒传"};
double[] prices = {1.1, 2.2, 3.3};
Document document = DocumentHelper.createDocument();
Element booksEle = document.addElement("books"); 创建父节点
for (int i = 0; i < id_s.length; i++)
{
Element bookEle = booksEle.addElement("book"); //这里addElement是已经将此Element添加到books节点下了
Element priceEle = bookEle.addElement("price");
Element titleEle = bookEle.addElement("title");
priceEle.setText(String.valueOf(prices[i]));
titleEle.setText(titles[i]);
bookEle.addAttribute("id", String.valueOf(id_s[i]));
}
OutputFormat format = OutputFormat.createPrettyPrint(); //以缩进的格式保存
format.setEncoding("UTF-8");
XMLWriter out = new XMLWriter(new FileOutputStream("f:\\book_1.xml"), format);
out.write(document);
}
- 使用DOM4J进行读操作
private static void readXML_2() throws Exception
{
File file = new File("f:\\book_1.xml");
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new FileInputStream(file));
Element rootElement = document.getRootElement();
//System.out.println(rootElement.getName());
List bookList = rootElement.elements("book");
Iterator iter = bookList.iterator();
while (iter.hasNext())
{
Element bookEle = iter.next();
System.out.println("id = " + bookEle.attributeValue("id") + ",");
System.out.println("title = " + bookEle.elementText("title") + ",");
System.out.println("price = " + bookEle.elementText("price"));
}
}
话不多说,记录一下这两天学习XML的成果,预防忘记。详细的流程就不说明了,看一看就能回忆起。
XML在实际项目开发中是不可回避的,熟悉XML是有好处了,在很多框架中,也用到了XML的配置文件,学习XML的目的并仅限于使用,更多的是了解它的历史、好处、坏处,以及设计思想!
如果代码或者思路有错误或者有更多优秀的方法,希望各位路过的大佬指出,在此感谢!