首页 > 技术文章 > 关于XML的一些总结

zhuchaoli 2019-02-20 12:16 原文

  • xml的知识结构图

  eXtensible Markup Language,可扩展标记语言,简称XML,和HTML比较而言,语法相似,作用不同

  XML被设计用来存储和传输数据,但存储数据方面,数据库是主流;传输数据方面会越来越多的使用JSON数据格式;

  另一个额外的作用就是作为项目的配置文件使用,但这方面注解会越来越流行

  • xml语法
  1. 必须以XML声明开头  <?xml version="1.0" encoding="UTF-8"?>
  2. 必须拥有唯一的根元素
  3. 元素可以包含若干属性、子元素以及文本内容
  4. 开始标签必须与结束标签相匹配
  5. 标签必须正确地嵌套,不能交叉
  6. 标签名大小写敏感
  7. 支持实体字符和CDATA区 <![CDATA[ ]]>
  8. 有的空白字符是有意义的,不应该被忽略
<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="u001" name="蛋蛋">
        <email>dandan@rupeng.com</email>
        <phones>
            <phone>13700000001</phone>
            <phone>18000000001</phone>
        </phones>
    </user>
</users>
  • DTD约束

  通过约束可以限定XML文件结构,有助于确保数据的正确性,也为校验XML提供了依据。使用DTD约束XML时,可以规定文档包含哪些元素、元素顺序、元素个数、子元素情况、属性及属性值、默认值等等

  DTD约束语法

  元素声明:<!ELEMENT 元素名称 元素内容>

  属性声明:<!ATTLIST 元素名称  属性列表>

  元素内容的类型:ANY、EMPTY、#PCDATA、子元素列表

    子元素列表中可使用一些特殊符号:

         ,  逗号表示元素按声明顺序出现

         |  表示元素只能出现其中一个元素

         +   表示元素至少出现一次

         表示元素可以出现0次或多次

         ?  表示元素出现0次或1次

  属性类型:ID、CDATA、(enum1|enum2|enum3..)枚举

  属性值约束:、默认值、#REQIRED、#IMPLIED

<!ELEMENT users (user*)>
<!ELEMENT user (email+,phones?)>
<!ELEMENT email (#PCDATA)>
<!ELEMENT phones (phone*)>
<!ELEMENT phone (#PCDATA)>
<!ATTLIST user 
    id ID #REQUIRED
    name CDATA #IMPLIED
>

  可以把上面的DTD约束代码单独放在一个.dtd文件中,然后使用<!DOCTYPE>引用

  引用本地DTD文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE users SYSTEM "users.dtd">
<users>
    <user id="u001"  name="蛋蛋">
        <email>dandan@rupeng.com</email>
        <phones>
            <phone>13700000001</phone>
            <phone>18000000001</phone>
        </phones>
    </user>
</users>

  引用网上DTD文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE users PUBLIC "dtd名称" "DTD文件路径">
<users>
    <user id="u001"  name="蛋蛋">
        <email>dandan@rupeng.com</email>
        <phones>
            <phone>13700000001</phone>
            <phone>18000000001</phone>
        </phones>
    </user>
</users>
  • schema约束

  schema是另一种XML约束方式,它比DTD更加复杂,但功能更强大

    schema文件本质上是XML文件,约束步骤如下:

  1 由W3C组织事先定义好一组基本规则

使用<element>定义一个新元素

使用<complexType>表示此元素为复合元素

使用<sequence>表示子元素需要按照定义的顺序出现

使用<attribute>定义元素的属性

. . .

  2 由开发人员使用上述基本规则定义自己的规则

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="mystudents" >
    <element name="students" >
        <complexType>
            <sequence>
                <element name="student" maxOccurs="unbounded">
                    <complexType>
                        <sequence>
                            <element name="name" type="string"></element>
                        </sequence>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

  3 开发人员使用自己的规则约束自己的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
           xmlns="mystudents" xsi:schemaLocation="mystudents /students.xsd">
    <student>
       <name>蛋蛋</name>
    </student>
    <student>
       <name>建国</name>
    </student>
</students>

  由于schema语法太过庞杂,而且工作时几乎不会自己去写schema文件,所以只需要了解schema的原理,会引入现有的schema文件即可

  • xml的解析

  无论XML用来存储数据、传递数据还是做配置文件,终究都需要解析XML文件取出想要的数据。XML文件解析有多种方式,这里只介绍DOM解析方式和SAX解析方式。JDK对这两种方式都提供了支持,相关API分布在javax.xml、org.w3c.dom、org.xml.sax包及其子包下。

  DOM解析方式

   XML DOM和JavaScript DOM非常相似,有两个核心类org.w3c.dom.Document和org.w3c.dom.Element

   Document表示整个XML文档,提供了getElementsByTagName()和getElementById()等方法查找想要操作的Element对象

   Element表示XML元素,通过getAttribute()、getTextContent()、getElementsByTagName()等方法分别获得属性值、获得元素体文本内容、查找子元素等

public class DOMTest {
    public static void main(String[] args) throws Exception {
        // 解析users.xml,得到List<User>
        // 获得document对象
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        String path = DOMTest.class.getResource("/users.xml").getFile();
        Document document = documentBuilder.parse(path);

        List<User> userList = new ArrayList<User>();

        //获得所有的user元素
        NodeList userNodeList = document.getElementsByTagName("user");

        for (int i = 0; i < userNodeList.getLength(); i++) {
            User user = new User();

            Element userElement = (Element) userNodeList.item(i);
            String name = userElement.getAttribute("name");
            user.setName(name);
            String id = userElement.getAttribute("id");
            user.setId(id);

            //获得当前user下的所有email子元素
            NodeList emailNodeList = userElement.getElementsByTagName("email");
            for (int j = 0; j < emailNodeList.getLength(); j++) {
                Element emailElement = (Element) emailNodeList.item(j);
                String email = emailElement.getTextContent();
                user.setEmail(email);
            }

            List<String> phones = new ArrayList<String>();
            //获得当前user下的所有phone子元素
            NodeList phoneNodeList = userElement.getElementsByTagName("phone");
            for (int m = 0; m < phoneNodeList.getLength(); m++) {
                Element phoneElement = (Element) phoneNodeList.item(m);
                String phone = phoneElement.getTextContent();
                phones.add(phone);
            }
            user.setPhones(phones);
            userList.add(user);
        }
        System.out.println(userList);
    }
}

  SAX解析方式

   SAX(Simple API for XML)基本思路:在读取XML文件内容的过程中,会按照文件结构有规律的发生读取开始标签、读取标签体内容、读取结束标签这三种动作,

  开发人员可以根据XML文件结构特点,当发生不同动作的时候进行不同的处理,最终获取想要的数据。

  解析过程如下:

  1 编写处理器类,对不同的动作进行不同的处理

public class UserXMLHandler extends DefaultHandler {

    private User user;
    private String content; // 临时记录一个标签的文本内容
    public User getUser() {
        return user;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // System.out.println("读取到" + qName + "的开始标签");
        if ("user".equals(qName)) {
            user = new User();
            String id = attributes.getValue("id");
            String name = attributes.getValue("name");
            user.setId(id);
            user.setName(name);
        } else if ("email".equals(qName)) {

        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // System.out.println("读取到一段文本内容:" + new String(ch, start, length));
        content = new String(ch, start, length);
    }
@Override
public void endElement(String uri, String localName, String qName) throws SAXException { // System.out.println("读取到" + qName + "的结束标签"); if ("email".equals(qName)) { user.setEmail(content); } else if ("phone".equals(qName)) { user.setPhone(content); } } }

  2 执行解析并获取解析结果

public static void main(String[] args) throws Exception {
    File xmlFile = new File(SAXTest.class.getResource("/user.xml").getFile());
    UserXMLHandler userXMLHandler = new UserXMLHandler();

    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    SAXParser saxParser = saxParserFactory.newSAXParser();
    saxParser.parse(xmlFile, userXMLHandler);

    User user = userXMLHandler.getUser();
    System.out.println(user);
}

 

推荐阅读