美文网首页Java我爱编程
java学习笔记#7-XML

java学习笔记#7-XML

作者: edwin1993 | 来源:发表于2017-08-21 16:48 被阅读0次

    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

    相关文章

      网友评论

        本文标题:java学习笔记#7-XML

        本文链接:https://www.haomeiwen.com/subject/kcivkxtx.html