【Java高级特性】java学习之旅38-xml的解析方式

定义:Extensible Markup Language 可扩展标记语言

特点:

  • XML与编程语言无关
  • 可以实现不同编程语言实现的系统之间的数据转换

用途:

  1. 数据交换
  2. 实现项目的配置文件

和json对比:

  1. json比xml更加的轻量级
  2. xml比json更可读,结构更清晰

注意事项:

  1. xml使用的都是双标签
  2. xml标签名对大小写敏感
  3. 标签名建议使用字母加数字,不可使用特殊字符,不可使用空格
  4. 属性节点不建议使用< > " ’ &
  5. 建议同级标签要缩进对齐

解析的方式:

  1. DOM解析方式:基于dom数,把文档中的所有元素,按照其出现的层次关系,解析成一个个Node(节点) 对象
  • 有点:把XML文件在内存中构建属性结构,可以遍历和修改节点。
  • 缺点:如果文件比较大,内存有压力,解析的时间会比较长
  • 适用:修改XML数据
  1. SAX解析方式:事件驱动,逐行扫描文档,一边扫描一边解析。相当于DOM,SAX可以在解析文档的任意时刻停止解析,是一种速度更快,更高效方法。
  • 优点:解析可以立即开始,速度快,没有内存压力
  • 缺点:不能对节点做修改
  • 适用:读取XML文件
  1. DOM4J解析方式,有着更复杂的api,所以dom4j比jdom有更大的灵活性,DOM4J性能最好,连Sun的JAXM也在用DOM4J,目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J
  • 优点: 灵活性高,易用性和功能强大,性能优异
  • 缺点:复杂的api,移植性差
  • 适用:自行选择
  1. JDOM解析方式:JDOM是处理xml的纯java api。使用具体类而不是接口,JDOM具有树的的遍历,又有SAX的java规则,JDOM和DOM主要有两个方面不同。首先,JDOM仅使用具体类而不使用,这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。JDOM本身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器已将JDOM表示输出成SAX2事件流,DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码
  • 优点:基于dom树,比dom更简单,速度快
  • 缺点:如果文件比较大,内存有压力,不支持DOM中相应的遍历包
  • 适用:自行选择

使用:
解析: books.xml

<?xml version="1.0" encoding="UTF-8"?> 
<!-- xml文件的声明:xml文件遵循xml1.0版本格式协议,文本编码采用utf-8 -->
<books> <!-- 根节点:只能有一个 -->
	<book id="1"> <!-- book是`元素节点`,id是`属性节点` -->
		<name>java从入门到放弃</name> <!-- name是元素节点,文本内容是`文本节点` -->
		<author>王子玉</author>
		<page>10</page>
	</book>
	<book id="2">
		<name>mysql从删库到跑路</name>
		<author>张三</author>
		<page>20</page>
	</book>
</books>

实体类:

public class Book {
	
	private Long id;
	
	private String name;
	
	private String author;
	
	private Integer page;
	}
  1. DOM解析方式(读操作)
public static void main(String[] args){
    ArrayList<Book> bookEmptyList = new ArrayList<>();
    Book bookEmpty = null;
    
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try{
        //通过创建documentBuilder对象来对xml文件对象进行解析
        DocumentBuilder db = dbf.newDocumentBuilder();
        //解析完成之后会返回一个(w3c)document对象
        Document document = db.parse("books.xml");
        //获取xml文件对象当中的全部book标签对象并以节点集合的形式来进行返回操作
        NodeList bookList = document.getElementsByTagName("book");
        System.out.println("一共有" + bookList.getLength() + "本书。");
        //对book标签节点集合对象进行遍历操作
        for (int i = 0; i < bookList.getLength(); i ++){
            System.out.println("开始遍历第" + (i + 1) + "本书的内容");
            //建一个book的实体类用来存放解析出来的信息
            bookEmpty = new Book();
            //对集合数组对象当中的元素开始进行遍历操作,获取节点集合当中的节点对象
            Node book = bookList.item(i);
            //获取当前节点对象当中的全部的属性值对象并将其存放到map集合对象当中去
            NamedNodeMap attrs = book.getArrtibutes();
            //对当前节点当中的全部属性值进行遍历操作
            System.out.println("第" + (i + 1) + "本书共有" + attrs.getLength() + "个属性");
            for(int j = 0; j < attrs.getLength(); j++) {
                //获取属性集合对象当中的第i个属性节点对象
                Node attr = attrs.item(j);
                //输出节点的名字
                System.out.println("属性名:" + attr.getNodeName());
                //输出节点的值
                System.out.println("属性值:" + attr.getNodeValue());
            }
            
            //得到当前book对象的所有子节点对象,并且以一个节点集合的形式来进行返回操作
            NodeList childNode = book.getChildNodes();
            //遍历book节点的全部子节点对象
            System.out.println("第" + (i + 1) + "本书当中共有" + childNode.getLength() + "个子节点");
            //这里会显示有9个子节点,但是在xml文档当中可以看到只有四个子节点,是因为系统会自动的将book标签于子节点,子节点和子节点之间的空格+换行看作是一个节点,对book标签当中的子节点进行遍历输出操作
            for (int k = 0; k < childNode.getLength(); k++) {
                //对子节点集合当中的第K项子节点的名字进行输出操作
                //只对含有标签对象的元素节点进行输出操作,对为空白的文本对象节点(#text)不进行输出操作
                System.out.println("第" + (k + 1) + "个节点的节点名" + childNode.item(k).getNodeName());
                //获取子节点对象的文本内容
                System.out.println("节点的值是" + childNode.item(k).getTextContent());
            }
        }
        
    }
}

(写操作)

public static void main(String[] args) throws Execption {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document document = db.newDocument();
    
    //创建books根节点
    Element books = document.createElement("books");
    //创建book节点
    Element book1 = document.createElement("book");
    //给book节点设置属性名和属性值
    book1.setArrribute("id", "1");
    //创建name节点
    Element name1 = document.createElement("name");
    //创建author节点
    Elemtent author1 = document.createElement("author");
    //创建page节点
    Element page1 = document.createElement("page");
    
    //将name author page节点设置为book节点的子节点
    book1.appendChild(name1);
    book1.appendChild(author1);
    book1.appendChild(page1);
    
    //设置name author page的文本节点
    name1.setTextContent("java从入门到到放弃");
    author1.setTextContent("王子玉");
    page1.setTextContent("10");
    
    //将book节点作为book1的节点的子节点
    books.appendChild(book1);
    
    Element book2 = document.createElement("book");
    book2.setAttribute("id", "2");
    Element name2 = document.createElement("name");
    Element author2 = document.createElement("author");
    Element page2 = document.createElement("page");
    book2.appendChild(name2);
    book2.appendChild(author2);
    book2.appendChild(page2);
    name2.setTextContent("mysql从删库到跑路");
    author2.setTextContent("韩文龙");
    page2.setTextContent("20");
    books.appendChild(book2);
    
    //将books节点添加到dom数中
    document.appendChild(books);
    
    TransformerFactory tff = TransformerFactory.newInstance();
    Transformer tf = tff.newTransformer();
    
    //设置换行
    tf.setOutputProperty(OutputKeys.INDENT, "yes");
    //设置缩进
    tf.setOutputProperty(
            "http://xml.apache.org/xslt}indent-amount" , "2");
            
    tf.transform(new DOMSource(document), new StreamResult(new File("book_dom.xml")));
}
  1. SAX解析:
public static void main(String[] args) throws Exception {
    //获取SAX解析工厂对象
    SAXParserFactory factory = SAXParserFactory.newInstance();
    //调用工厂的newSAXParser方法获取SAXParser解析器对象
    SAXParser parser = factory.newSAXParser();
    //获取MyHander对象,为了得到XML文件对应的资源
    MyHander dh = new MyHander();
    //使用SAXParser解析器对象调用parse方法解析XML文件
    parser.parse("NewFile.xml", dh);
    //用get方法拿到MyHander中的Book型List集合
    List<Book> bookList = dh.getBooks();
    //打印输出
    for(Book book : bookList) {
        System.out.println(book);
    }
}
//新建一个MyHander,该类需要继承DefaultHander后者实现ContentHander接口,
//这里我们使用继承DefaultHander的方式,该类是SAX解析的核心,需要重写几个方法,如下:
//1. startDocument(): 文档解析开始时调用,该方法只会调用一次
//2. startElements(String uri, String localName, String qName, Attributes attrubutes)
//节点解析式开始时调用
//url:xml文档的命名空间
//localName:节点的名字
//qName: 带命名空间节点的名字
//attributes: 节点的属性集

//3. characters(char[] ch, int start, int length):解析标签的内容的时候调用
//ch:当前读取到的TextNode(文本节点)的字节数组
//start: 字节开始的位置,为0就是从0开始读,全部读取
//length: 当前TextNode的长度

//4. endElements(String uri, String localName, String qName):节点解析结束后调用

//5. endDocument(): 文档解析结束后调用,该方法只会调用一次

public class MyHander extends DefaultHandler {
    //初始化一个List数组
    private List<Book> books =  new ArrayList<>();
    //用来记录当前的book
    private Book book = null;
    //提供一个getBooks()的方法,以便外部湖区List集合books
    public List<Book> getBooks() {
        return books;
    }
    
    boolean bName = false;
    boolean bAuthor = false;
    boolean bPage = false;
    
    //节点开始解析
    @Override
    public void startElenment(String url, String localName, String qName, Attributes attributes) throws Exception {
        super.startElement(url, localName, qName, attributes);
        if(qName.equals("book")) {
            String id = attributes.getValue("id");
            book = new Book();
            book.setId(Long.parseLong(id));
        }else if (qName.equals("name")) {
            bName = true;
        }else if (qName.equals("author")) {
            bAuthor = true;
        } else if (qName.equals("page")) {
            bPage = true;
        }
    }
    
    //开始解析节点时候调用
    @Override
    public void characters(char[] ch, int start, int length) throws Exception {
        super.character(ch, start, length);
        if(bName) {
            book.setName(new String(ch, start, length));
            bName = false;
        } else if (bAuthor) {
            book.setAuthor(new String(ch, start, length));
        } else if (bPage) {
            book.setPage(Integer.parseInt(new String(ch, start, length)));
            bPage = false;
        }
    }
    
    //结束时调用
    @Override
    public void endElement(String url, String localName, String qName) thorws Exception {
        super.endElement(url, localName, qName);
        if (qName.equals("book")) {
            books.add(book);
        }
    }
}
  1. 使用dom4j解析xml(读操作) 需要导入dom4j的jar包
public static void main(String[] args) {
    ArrayList<Book> books = new ArrayList<>();
    
    SAXReader read = new SAXReader();
    //获取document文件
    Document document = null;
    try{
        document = read.read(new File("books.xml"));
    } catch (DocumentExceprion e) {
        System.out.pirntln("没有找到文件");
    }
    //获取根节点
    Element root = document.getRootElement();
    //迭代器
    Iterator rootIt = root.elementIterator();
    while (rootIt.hasNext()) {
        Book book = new Book();
        Element element = (Element) rootIt.next();
        //获取属性元素
        List<Attribute> attrubytes = element.attributes();
        for (Attribute attribute : attributes) {
            if (attribute.getName().equals("id")) {
                book.setId(Long.valueOf(attribute.getValue()));
            }
        }
        //迭代器
        Iterator child = element.elementIterator();
        while(child.hasNext()) {
            Element child Element = (Element) child.next();
            //获取元素名字
            String name1 = childElement.getName();
            //获取元素的值
            String value = childElement.getStringValue();
            switch (name1) {
                case "name":
                    book.setName(value);
                    break;
                case "author":
                    book.setAuthor(value);
                    break;
                case "page":
                    book.getPage(Integer.valueOf(value));
                    break;
            }
        }
        books.add(book);
    }
    books,forEach(System.out::println);
}

(写操作)

public staic void main(String[] args) {
    String path = "books_Dom4j.xml"
    Document doc = DocumentHelper.createDocumemt();
    
    //创建根对象
    Element root  = doc.addElement("books");
    
    //创建一个一级子级对象
    Element book1 = root.addElement("book");
    
    //给一级子元素添加属性值
    book1.setAttribute("id", "1");
    
    //给一级子元素添加二级子元素
    Element name1 = book1.addElement("name");
    nam1.setText("遮天");
    Element author1 = book1.addElement("author");
    author1.setText("辰东");
    Element page1 = book1.addElement("page");
    page1.setText("123");
    
    Element name2 = book2.addElement("name");
    name2.setText("莽荒纪");
    Element author2 = book2.addElement("author");
    author.setText("我吃西红柿");
    Element page2 = book2.addElement("page");
    page2.setText("567");
    
    //6. 设置输出流来生成一个xml文件
    OutputStream os = null;
    try {
        os = new FileOutputStream(path);
    } catch (FileNotFoundException e) {
        System.out.println(e.getMessage());
    }
    
    //设置输出格式
    OutputFormat format = OutputFormat.createPrettyPrint();
    //设置xml编码
    format.setEncoding("utf-8");
    //写:两个参数,第一,输出流的xml文件在哪。第二,表示设置xml的格式
    XMLWriter xw = null;
    try{
        xw = null;
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    try{
        xw = new XMLWriter(os, format);
    } catch (UnsupportedEncodingExceprion e) {
        e.printStackTrace();
    }
    //将组合好的xml封装到已经创建好的document对象中,写出真是存爱的xml文件中
    try {
        xw.write(doc);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    //清空缓存
    try {
        xw.flush();
        xw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. 使用JDOM解析XML(需要jdom的jar包)
public void readXML() throws Excprion {
    //1. 创建一个解析器SAXBuilder
    SAXBuilder builder = new SAXBuilder();
    //2. 创建一个文件输入流
    FileInputStream fis = new FileInputStream("books_jdom.xml");
    //3. 将流加载到解析器中
    org.jdom2.Document doc = builder.build(fis);
    //4. 获取文档的根节点
    Element book = doc.getRootElement();
    //5. 对根节点进行遍历
    getAllElement(book);
}

private void getAllElement(Element node) {
    List<Attribute> attributes = node.getAttributes();
    System.out.pirntln("节点:" + node.getName() + "内容:" + node.getText().trim());
    if(node.hasArributes()) {
        for (Attrubute attr : attrubutes) {
            System.out.pirntln("属性" + attr.getName()  + "值:" + attr.getValue());
        }
    }
    
    List<Element> children = node.getChildren();
    for (Element element : children) {
        getAllElement(element);
    }
}

写操作:

public void writeXML() throws IOException {
    // 创建一个根节点
    Element books = new Element("books");
    Document doc = new Document(books);
    //在根节点下创建第一个子节点
    Element book1 = new Element("book");
    book1.setAttrubute(new Attribute("id", "001"));
    //在第一个子节点下创建第一个子节点
    Element name1 = new Element("name");
    name1.setText("java从放弃到入门");
    Element author1 = new Element("author");
    author1.setText("王子玉");
    //在第一个子节点下创建第三个子节点
    Element page1 = new Element("page");
    page1.setText("35");
    
    //在根节点下创建第二个子节点
    Element book2 = new Element("book");
    book2.setAttribute(new Attribute("id", "002"));
    //在第二个子节点下创建第一个子节点
    Element name2 = new Element("name");
    name2.setText("mysql从删库到跑路");
    //在第二个子节点下创建第二个子节点
    Element author2 = new Element("author");
    author2.setText("韩文龙");
    //在第二个子节点下创建第三个子节点
    Element page2 = new Element("page");
    page2.setText("53");
    
    books.addContent(book1);
    books.addContent(book2);
    
    book1.addContent(name1);
    book1.addContent(author1);
    book1.addContent(page1);
    
    book2.addContent(name2);
    book2.addContent(author2);
    book2.addContent(page2);
    
    //格式化
    Format format = Format.getCompactFormat();
    format.setEncoding("utf-8");
    //保证输出后的xml的格式
    format.setIndent("  ");
    XMLOutputter out = new XMLOutputter(format);
    ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
    out.output(doc, byteRsp);
    String str = byteRsp.toString("utf-8");
    System.out.println(str);
    
    out.output(doc, new FileOutputStream("books_jdom.xml"));
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JeffHan^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值