java学习笔记#7-XML

XML简介

XML常被用于数据存储和传输,其存储结构是树状的,它的重要性来自于以下几点:

  • 不同程序之间的通信
  • 不同平台之间的通信
  • 不同平台之间的数据共享
XML存储结构.png

下面给出一个XML的简单结构

<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
    <book id = "01">
        <name>日记</name>
        <author>Edwin</author>
        <price>99</price>
    </book>
    <book id = "02">
        <name>童话</name>
        <price>99</price>
        <language>English</language>
    </book>
    <book>
        <id>03</id>
        <!--属性可以用内部标签去表示-->
    </book>
</bookstore>

XML在JAVA中的使用

Java中要获取xml文件的内容有四种解析方式:
DOM:官方提供的解析方式、不需要额外jar包;
SAX:官方提供的解析方式、不需要额外jar包;
DOM4J:其它组织所提供,需要额外的jar包支持;
JDOM:其它组织所提供,需要额外的jar包支持;

DOM方法解析XML:

解析XML属性
public void analyzeXML(){
//        创建DocumentBuilderFactory对象
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

        try {
//        创建DocumentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//        通过DocumentBuilder的parse(String FileName)方法解析XML文件
            Document document = documentBuilder.parse("./XMLLearningFolder/Book.xml");
            NodeList bookList = document.getElementsByTagName("book");
            for (int i = 0;i <bookList.getLength();i++){
                Node book = bookList.item(i);
//                获取book结点所有属性
                NamedNodeMap attrs = book.getAttributes();
                for (int j = 0; j < attrs.getLength(); j++) {
                    Node attr = attrs.item(j);
//                    System.out.println(attr);
                    System.out.println("attribute name:" + attr.getNodeName());
                    System.out.println("attribute value:" + attr.getNodeValue());
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

除了NamedNodeMap attrs = book.getAttributes();获取所有属性依次遍历外,还可以通过强制转换node到element来使用element中的方法获取属性值。

//                用element的方法输出:
                Element elementBook = (Element)bookList.item(i);
                String attrValue = elementBook.getAttribute("id");
                System.out.println("id:"+attributeString);
解析XML子节点
//                用node中的getChildNodes获得所有子节点
                NodeList childNodes = book.getChildNodes();
//                子节点中包括换行符等,解析中也视为子节点
                System.out.println("No."+ (i+1) +"book has " +childNodes.getLength()+" childNodes");
                for (int j = 0; j <childNodes.getLength() ; j++) {
                    System.out.println(childNodes.item(j).getNodeName());
                }
节点类型.png

所以对应的输出结果为:

输出结果.png

通过上面的表格可以看出,element节点无法获取value值,因为它只识别标签,对标签内部的内容不作解析,所以要获取内容的解析方式:

                for (int j = 0; j <childNodes.getLength() ; j++) {
                    if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE){
                        System.out.println(childNodes.item(j).getNodeName());
                        System.out.println(childNodes.item(j).getFirstChild().getNodeValue());
//                        或者:
//                        System.out.println(childNodes.item(j).getTextContent());
                    }
                }

区别:
当XML文件内容如下:

...
    <book id = "01">
        <name><a>aa</a>日记</name>
...

输出:

两个方法输出的差异:.png

因为getFirstChild获取了element 所以value 为null。

SAX方法解析XML

//        获取SAXParserFactory实例
        SAXParserFactory saxParserFactory =  SAXParserFactory.newInstance();
        try {
//            通过factory获取SAXParser实例
            SAXParser saxParser = saxParserFactory.newSAXParser();
//            创建SAXParserHandler对象
            SAXParserHandler handler = new SAXParserHandler();
            saxParser.parse("./XMLLearningFolder/Book.xml",handler);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e){
            e.printStackTrace();
        }

在调用parse时:saxParser.parse("./XMLLearningFolder/Book.xml",handler);
因为参数需要DefaultHandler,所以要创建一个继承DefaultHandler的类

package pres.edwin.usingXML;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Created by Edwin_1993 on 2017/8/18.
 */
public class SAXParserHandler extends DefaultHandler{
    /**
     * 用于遍历xml文件的开始标签
     * @param uri
     * @param localName
     * @param qName 标签名
     * @param attributes
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        if (qName.equals("book")){
//            已知属性名称是id:
            String value = attributes.getValue("id");
            System.out.println("book id :" + value);
//            不知道属性名称和个数:
            int attributeNum = attributes.getLength();
            for (int i = 0; i < attributeNum; i++) {
                System.out.println("book attribute NO."+(i+1)+ " name :"+attributes.getQName(i) + "value:"+attributes.getValue(i));
                
            }
        }else if (!qName.equals("bookstore")){
//            层层递归到内部的其他节点
            System.out.println("节点名" + qName );
        }
    }

    /**
     * 用于遍历xml文件的结束标签
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
//        添加针对的节点名:
        if (qName.equals("book")){
            System.out.println("----end----");
        }
    }

    /**
     * 标识解析开始
     * @throws SAXException
     */
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("SAX analyze start");
    }

    /**
     * 标识解析结束
     * @throws SAXException
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("SAX analyze end");
    }

    /**
     * 获取节点内的具体内容
     * @param ch 节点中所有内容
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
//        同样,所有的回车等也会被认为是值进行获取
        String value = new String(ch,start,length);
//        通过trim()去除所有的空格回车
        if (!value.trim().equals("")){
            System.out.println("节点值"+value);
        }
    }
}

JDOM方法解析XML

与上面所提到的两种解析方式不同,JDOM解析非JAVA官方所提供,需要添加JDOM包

实现方式及说明:

SAXBuilder saxBuilder = new SAXBuilder();
//        将xml文件作为输入流进行引入
        InputStream in = null;
        try {
            in = new FileInputStream("./XMLLearningFolder/Book.xml");
            org.jdom2.Document document = saxBuilder.build(in);
//            如果有乱码 需要在读入的时候选择解析的字符集
//            InputStreamReader inWithCode = new InputStreamReader(in,"UTF-8");
//            org.jdom2.Document document = saxBuilder.build(inWithCode);

//            document对象用于获取xml根节点
            Element rootElement = document.getRootElement();
            List<Element> bookList = rootElement.getChildren();
            for (Element book :bookList){
                System.out.println("开始解析第"+ (bookList.indexOf(book) + 1)+"本书。");
//                获取内部属性(清楚内部的属性数量和名字):
//                book.getAttributeValue("id");
//                获取内部属性(不清楚内部的属性数量和名字):
                List<Attribute> attributeList = book.getAttributes();
                for (Attribute attribute:attributeList){
                    System.out.println(attribute.getName() + "---" + attribute.getValue());
                }

//                便利内部子节点:
                List<Element> bookChildList = book.getChildren();
                for (Element element : bookChildList){
                    System.out.println("节点名:" + element.getName() + "--节点值:"+ element.getValue());
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

DOM4J方法解析XML

DOM4J也需要引入Jar包

具体实现及说明:

//        创建SAXReader
        SAXReader saxReader = new SAXReader();
        try {
            org.dom4j.Document document = saxReader.read(new File("./XMLLearningFolder/Book.xml"));
//            获取document的根节点
            org.dom4j.Element bookStore = document.getRootElement();
//            通过elements的elementIterator 获取迭代器
            Iterator iterator = bookStore.elementIterator();

            while(iterator.hasNext()){
                org.dom4j.Element book = (org.dom4j.Element)iterator.next();
                List<org.dom4j.Attribute> bookAttributes = book.attributes();
                for (org.dom4j.Attribute attribute : bookAttributes){
                    System.out.println(attribute.getName()+"---"+attribute.getValue());
                }
                Iterator innerIter = book.elementIterator();
                while (innerIter.hasNext()){
                    org.dom4j.Element bookChild = (org.dom4j.Element)innerIter.next();
                    System.out.println(bookChild.getName()+"----"+bookChild.getStringValue());
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

四种解析方式的对比

DOM:一次性加载xml文件进入内存,树状结构便于解析与修改。
SAX:基于事件的解析方式,对内存的消耗比较少,触发例如startelement endelement。适用于只处理xml中的数据。
JDOM:使用集体类而不使用接口。
DOM4J:JDOM的智能分支,使用接口类与抽象基本方法类,优点很多。使用范围非常广。

四种XML的生成方式

DOM

    public void createXMLByDOM(){
        DocumentBuilderFactory documentBuilderFactory  = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            org.w3c.dom.Document domDocument = documentBuilder.newDocument();
            domDocument.setXmlStandalone(true);
            org.w3c.dom.Element bookStore = domDocument.createElement("bookStore");
//            添加子节点
            org.w3c.dom.Element book = domDocument.createElement("book");
            org.w3c.dom.Element bookName =domDocument.createElement("name");
            bookName.setTextContent("书名为。。。");
            book.appendChild(bookName);
            book.setAttribute("id","1");
            bookStore.appendChild(book);
//            添加根节点
            domDocument.appendChild(bookStore);
//            将现有DOM树转为xml文件
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
//            设置输出格式,INDENT 换行
            transformer.setOutputProperty(OutputKeys.INDENT,"yes");
            transformer.transform(new DOMSource(domDocument),new StreamResult(new File("XMLLearningFolder/newDomBooks.xml")));

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }
运行结果.png

SAX

public void createXMLBySAX(){
//        创建TransformerFactory对象
        SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        try {
//            创建TransformerHandler对象
            TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
//            创建transformer对象
            Transformer transformer = transformerHandler.getTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");
            transformer.setOutputProperty(OutputKeys.INDENT,"yes");

//            创建result对象
            File outFile =  new File("XMLLearningFolder/newSAXBooks.xml");
            if (!outFile.exists()){
                outFile.createNewFile();
            }
            Result result = new StreamResult(new FileOutputStream(outFile));
//            将result对象与Handler关联
            transformerHandler.setResult(result);

//            打开document
            transformerHandler.startDocument();
            AttributesImpl attributes = new AttributesImpl();
//            创建节点,startElement endElement 一一对应。
            transformerHandler.startElement("","","bookStore",attributes);
            attributes.clear();
            attributes.addAttribute("","","id","","1");
            transformerHandler.startElement("","","book",attributes);
//            book内部节点创建
            attributes.clear();
            transformerHandler.startElement("","","name",attributes);
            String tempString = "书名为。。";
            transformerHandler.characters(tempString.toCharArray(),0,tempString.length());

//            依次结束节点
            transformerHandler.endElement("","","name");
            transformerHandler.endElement("","","book");
            transformerHandler.endElement("","","bookStore");

//            关闭document
            transformerHandler.endDocument();

        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }

    }
运行结果.png
注意几个方法的顺序:
  • (可选)setOutputProperty
  • transformerHandler.setResult(result);
  • transformerHandler.startDocument();
  • transformerHandler.endDocument();

DOM4J

DOM4J生成RSS格式的XML文件

public void createXMLByDOM4J(){
//        document相当于整个xml文件
        org.dom4j.Document document = DocumentHelper.createDocument();
//        创建根节点
        org.dom4j.Element rss = document.addElement("rss");
//        添加属性
        rss.addAttribute("version","2.0");
//        生成子节点
        org.dom4j.Element channel = rss.addElement("channel");
        org.dom4j.Element title = channel.addElement("title");
        title.setText("国内新闻");
//        设置格式
        OutputFormat outputFormat = OutputFormat.createPrettyPrint();
//        outputFormat.setEncoding("GBK");

//        生成xml文件
        File outFile = new File("XMLLearningFolder/newDOM4JXML.xml");
        try {
            XMLWriter writer = new XMLWriter(new FileOutputStream(outFile),outputFormat);
//            设置是否转义,默认值是true
            writer.setEscapeText(false);
            writer.write(document);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
运行结果.png

JDOM

public void createXMLByJDOM(){
//        生成根结点
        Element rootElement = new Element("rss");
        rootElement.setAttribute("version","2.0");
        Element channel = new Element("channel");
        rootElement.addContent(channel);
        Element title = new Element("title");
        title.setText("<内容内容>");
        channel.addContent(title);
//        节点间存在特殊字符转义,需要处理。
        Element context = new Element("context");
        context.addContent(new CDATA("<内容内容>"));
        channel.addContent(context);
//        生成document
        Document document = new Document(rootElement);
        Format format = Format.getCompactFormat();
        format.setIndent("");
//        format.setEncoding("gbk");
//        生成XMLOutputter 将document转为xml
        XMLOutputter xmlOutputter = new XMLOutputter(format);
        try {
            xmlOutputter.output(document,new FileOutputStream(new File("XMLLearningFolder/newJDOMXML.xml")));
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
运行结果.png

四种生成方法的对比:

DOM:基于tree,DOM树驻留内存,改动方便
SAX:基于事件,修改不易。
JDOM DOM4J:基于底层API

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容