BCSP-玄子Share-Java框基础_解析XML

二、XML

2.1 XML 简介

XML(Extensible Markup Language),可扩展标记语言

2.1.1 特点

  • XML 与操作系统、编程语言的开发平台无关
  • 规范统一,实现不同系统之间的数据交换

2.1.2 作用

  • 数据存储
  • 数据交换
  • 数据配置

2.1.3 XML 文档结构



<books>

	
	<book id="bk101">
        
		<title>.NET高级编程title>
		<author>王姗author>
		<description>包含C#框架和网络编程等description>
	book>
	<book id="bk102">
		<title>XML基础编程title>
		<author>李明明author>
		<description>包含XML基础概念和基本用法description>
	book>
books>

使用标签描述的文档元素信息,成对出现。

节点不包含子节点可自闭合</code></p> </blockquote> <h2>2.2 XML 标签</h2> <p>XML 文档的内容元素由一系列标签组成</p> <pre><code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>元素名</span> <span class="token attr-name">属性名</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>属性值<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>元素内容(子元素、字符等)<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>元素名</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 开始标签 --></span> <span class="token comment"><!-- 元素允许是空元素,语法:如<title>--></span> <span class="token comment"><!-- 结束标签 --></span> </code></pre> <h3>2.2.1 元素命名规则</h3> <ul> <li>名称中可以包含字母、数字或者其他的字符</li> <li>名称不能以数字或者标点符号开始</li> <li>名称不能以字符<code>xml</code>(或者XML、Xml)开始</li> <li>名称中不能含空格</li> </ul> <h3>2.2.2 属性语法规则</h3> <ul> <li>属性可以加在任何一个元素的起始标签上,但不能加在结束标签上</li> <li>属性值用双引号包裹</li> <li>一个元素可以有多个属性,多个属性之间用空格隔开</li> <li>属性值中不能直接包含<code> <、"、&</code></li> </ul> <h3>2.2.3 XML 中的特殊字符的处理</h3> <p>XML 中的特殊字符包括<code> < 、> 、' 、" 、&</code></p> <p>使用预定义实体对特殊字符进行转义</p> <table> <thead> <tr> <th>特殊字符</th> <th>实体名称</th> </tr> </thead> <tbody> <tr> <td><</td> <td><code><</code></td> </tr> <tr> <td>></td> <td><code>></code></td> </tr> <tr> <td>"</td> <td><code>"</code></td> </tr> <tr> <td>’</td> <td><code>'</code></td> </tr> <tr> <td>&</td> <td><code>&</code></td> </tr> </tbody> </table> <p>在元素的文本中使用 CDATA 节处理</p> <pre><code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>description</span><span class="token punctuation">></span></span> <span class="token cdata"><![CDATA[讲解了元素<title>以及的使用]]> description>

2.2.4 编写格式良好的 XML 文档

格式良好的 XML 文档需要遵循如下规则

  • 有 XML 声明语句
  • 有且仅有一个根元素
  • 标签大小写敏感
  • 属性值用双引号
  • 标签成对/空标签关闭
  • 元素正确嵌套

2.3 XML 解析技术

2.3.1 DOM

  • 基于 XML 文档树结构的解析
  • 适用于多次访问的 XML 文档
  • 比较消耗资源

2.3.2 SAX

  • 基于事件的解析
  • 适用于大数据量的 XML 文档
  • 占用资源少,内存消耗小

DOM 和 SAX 不针对特定语言,只是定义了一些接口,以及部分缺省实现(使用空方法实现接口)

2.3.3 JDOM

  • 针对 Java 的特定文档模型
  • 使用具体类而不使用接口
  • API 大量使用了 Java 集合类型

2.3.4 DOM4J

  • 非常优秀的开源 Java XML API
  • 面向接口编程,比 JDOM 更加灵活
  • 使用 Java 集合框架处理 XML

2.4 DOM 解析 XML 文档

2.4.1 DM 解析 XML 原理

文档对象模型(Document Object Model)DOM 把 XML 文档映射成一个倒挂的树

<book >
    <title>三国演义title>
    <author>罗贯中author>
    <price>30元price>
book>

使用 Oracle 提供的 JAXP(Java API for XML Processing)

  • org.w3c.dom:W3C 推荐的用于使用 DOM 解析 XML 文档的接
  • org.xml.sax:用于使用 SAX 解析 XML 文档的接口
  • javax.xml.parsers:解析器工厂工具,获得并配置特殊的分析器

2.4.2 解析 XML 文档实现步骤

  1. 创建解析器工厂 DocumentBuilderFactory 对象
  2. 由解析器工厂对象创建解析器 DocumentBuilder 对象
  3. 由解析器对象对 XML 文件进行解析、构建 DOM 树,创建相应的 Document 对象
  4. 以Document 对象为起点对 DOM 树的节点进行增加、删除、修改、查询等操作

2.4.3 解析 XML 部分常用 API

常用接口 说明 常用方法
Node 代表了文档树中的一个抽象节点,有 Document、Element、Text 等子对象 NodeList getChildNodes()
Node getFirstChild()
Node getLastChild()
Node getNextSibling()
Node getPreviousSibling()
Node appendChild(Node child)
String getNodeName()
String getNodeValue()
short getNodeType()
NodeList 包含了一个或多个节点(Node)的列表 int getLength()
Node item(int index)
Document 表示整个 XML 文档 NodeList getElementsByTagName(String tagname)
Element getElementById(String id)
Element getDocumentElement()
Element createElement(String tagname)
Element XML 文档中的一个元素,是 Node 最主要的子对象 String getAttribute(String name)
NodeList getElementsByTagName(String tagname)
String getTagName()

2.4.4 访问 DOM 树节点属性

显示 XML 文件中收藏的手机品牌和型号

BCSP-玄子Share-Java框基础_解析XML_第1张图片


<PhoneInfo>
    <Brand name="华为">
        <Type name="P90"/>
        <Item>
            <title>标题信息title>
            <link>链接link>
            <description>描述description>
            <pubDate>2023-02-01pubDate>
        Item>
    Brand>
    <Brand name="苹果">
        <Type name="iPhone Z"/>
        <Type name="iPhone ZL"/>
    Brand>
    <Brand name="三星">
        <Type name="NoteX"/>
    Brand>
PhoneInfo>
  • 演示案例一
public class Book {
    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
        NodeList bookList = doc.getElementsByTagName("Brand");
        for (int i = 0; i < bookList.getLength(); i++) {
            Node brand = bookList.item(i);
            Element element = (Element) brand;
            String attrVal = element.getAttribute("name");
            NodeList types = element.getChildNodes();
            for (int j = 0; j < types.getLength(); j++) {
                Node typeNode = types.item(j);
                if (typeNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element typeElement = (Element) typeNode;
                    String type = typeElement.getAttribute("name");
                    System.out.println("手机:" + attrVal + type);
                }
            }
        }
    }
}
  • 演示案例二
public class Xz01 {
    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
        NodeList brandList = DocumentBuilderFactory
                .newInstance()
                .newDocumentBuilder()
                .parse("src/main/resources/PhoneInfo.xml")
                .getElementsByTagName("Brand");

        for (int i = 0; i < brandList.getLength(); i++) {
            Element brandElement = (Element) brandList.item(i);
            System.out.println(brandElement.getTagName() + ":" + brandElement.getAttribute("name"));

            NodeList typeList = brandElement.getElementsByTagName("Type");
            for (int j = 0; j < typeList.getLength(); j++) {
                Element typeElement = (Element) typeList.item(j);
                System.out.println("\t" + typeElement.getTagName() + ":" + typeElement.getAttribute("name"));

                NodeList itemList = brandElement.getElementsByTagName("Item");
                for (int k = 0; k < itemList.getLength(); k++) {
                    Element itemElement = (Element) itemList.item(k);
                    NodeList pubDateList = itemElement.getElementsByTagName("pubDate");
                    System.out.print("\t" + itemElement.getTagName() + ":");
                    for (int l = 0; l < pubDateList.getLength(); l++) {
                        String textContent = pubDateList.item(l).getTextContent();
                        System.out.println(textContent);
                    }
                }
            }
        }
    }
}
//  Brand:华为
//        Type:P90
//        Item:2023-02-01
//  Brand:苹果
//        Type:iPhone Z
//        Type:iPhone ZL
//  Brand:三星
//        Type:NoteX

调用 Node 对象的 getChildNodes() 方法有时会包含 XML 文档中的空白符,导致调用 Node 对象方法出错,解决办法包括:

  1. 取得 Node 对象后判断node.getNodeType() == Node.ELEMENT_NODE,即判断是否是元素节
  2. 点将 Node 对象转换为 Element 对象,使用 Element 的 getElementsByTagName(String name)

2.4.5 访问 DOM 树节点内容

显示XML文件中手机新闻的发布日期

  • 演示案例
public class Book2 {
    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
        NodeList bookList = doc.getElementsByTagName("pubDate");
        Element pubDateElement = (Element) bookList.item(0);
        String nodeValue = pubDateElement.getFirstChild().getNodeValue();
        System.out.println(nodeValue);
    }
}
// 2023-02-01

2.4.6 添加 DOM 节点并保存

  • 演示案例
public class Book3 {
    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
        
        Element brandElement = doc.createElement("Brand");
        brandElement.setAttribute("name", "三星");
        
        Element typeElement = doc.createElement("Type");
        typeElement.setAttribute("name", "NoteX");
        
        brandElement.appendChild(typeElement);
        
        Element phoneInfoElement = (Element) doc.getElementsByTagName("PhoneInfo").item(0);
        phoneInfoElement.appendChild(brandElement);
        
        TransformerFactory tff = TransformerFactory.newInstance();
        Transformer tf = tff.newTransformer();
        DOMSource domSource = new DOMSource(doc);
        tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        StreamResult streamResult = new StreamResult(Files.newOutputStream(Paths.get("src/main/java/CH15_XML/PhoneInfo.xml")));
        tf.transform(domSource, streamResult);
    }
}
    <Brand name="三星">
        <Type name="NoteX"/>
    Brand>

2.4.7 修改或删除 DOM 节点

  • 演示案例
public class Book4 {
    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
        NodeList list = doc.getElementsByTagName("Brand");
        for (int i = 0; i < list.getLength(); i++) {
            Element brandItem = ((Element) list.item(i));
            String brandName = brandItem.getAttribute("name");
            if ("三星".equals(brandName)) {
                // ElementBrand.setAttribute("name", "OPPO");
                brandItem.getParentNode().removeChild(brandItem);
                // 先获取父节点,再删除子节点
            }
        }
        
        TransformerFactory tff = TransformerFactory.newInstance();
        Transformer tf = tff.newTransformer();
        DOMSource domSource = new DOMSource(doc);
        tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        StreamResult streamResult = new StreamResult(Files.newOutputStream(Paths.get("src/CH15_XML/PhoneInfo.xml")));
        tf.transform(domSource, streamResult);
    }
}

2.5 DOM4J 解析 XML 文档

2.5.1 DOM4J 常用 API

DOM4J 的主要接口都定义在 org.dom4j 包里

接口说明
Node:为所有的 DOM4J 中的 XML 节点定义了多态行为
Branch:为能够包含子节点的节点定义了公共行为
Element:定义 XML 元素
Document:定义 XML 文档
Entity:定义 XML 实体
Attribute:定义了 XML 的属性
DocumentType:定义 XML DOCTYPE 声明
ProcessingInstruction:定义 XML 处理指令
CharacterData:标识接口,标识基于字符的节点
Text:定义 XML 文本节点
CDATA:定义了 XML CDATA 区域
Comment:定义了 XML 注释的行为
常用接口 常用方法
Branch Element elementById(String id)
Element addElement(String name)
boolean remove(Node node)
Document Element getRootElement()
Element Element element(String name)
List elements()
List elements(String tagname)
Iterator elementIterator()
Iterator elementIterator(String name)
Attribute attribute(String name)
Element addAttribute(String name, String value)
String getText()

2.5.2 DOM4J 读取收藏信息

  • 演示案例
package CH15_XML;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.Iterator;

public class Book5 {
    public static void main(String[] args) throws DocumentException {
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File("src/main/java/CH15_XML/PhoneInfo.xml"));
        Element rootElement = document.getRootElement();
        for (Iterator<Element> itBrand = rootElement.elementIterator(); itBrand.hasNext(); ) {
            Element brand = itBrand.next();
            System.out.println(brand.attributeValue("name"));
            for (Iterator<Element> itType = brand.elementIterator(); itType.hasNext(); ) {
                Element type = itType.next();
                System.out.println("\t" + type.attributeValue("name"));
            }
        }
    }
}
//  华为
//	    P90
//	    null
//  苹果
//	    iPhone Z
//	    iPhone ZL
//  三星
//	    NoteX

你可能感兴趣的:(JAVASE,+,JAVAOOP,java,xml,python)