XML学习记录

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的目的并仅限于使用,更多的是了解它的历史、好处、坏处,以及设计思想!

如果代码或者思路有错误或者有更多优秀的方法,希望各位路过的大佬指出,在此感谢!

你可能感兴趣的:(XML学习记录)