XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言: 通过标签描述数据的一门语言(标签有时也称为元素),标签的名字是可以自定义的,XML文件是由很多标签组成的。而标签名是可以自定义的。

XML 不会做任何事情。XML 被设计用来结构化、存储以及传输信息,例如 Jani 写给 Tove 的便签,存储为 XML。

<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

XML 语言没有预定义的标签,而HTML 中使用的标签都是预定义的。HTML 文档只能使用在 HTML 标准中定义过的标签(如 <p><h1> 等等)。XML 允许创作者定义自己的标签和自己的文档结构。

XML 的作用

  1. 把数据从 HTML 分离

    通过 XML,数据能够存储在独立的 XML 文件中。这样就可以专注于使用 HTML/CSS 进行显示和布局,并确保修改底层数据不再需要对 HTML 进行任何的改变。通过使用几行 JavaScript 代码,就可以读取一个外部 XML 文件,并更新网页的数据内容。

  2. 简化数据共享

    XML 数据以纯文本格式进行存储,因此提供了一种独立于软件和硬件的数据存储方法。这让创建不同应用程序可以共享的数据变得更加容易。

  3. 简化数据传输

    由于可以通过各种不兼容的应用程序来读取数据,以 XML 交换数据降低了这种复杂性。

  4. 使数据更有用

    不同的应用程序都能够访问数据,不仅仅在 HTML 页中,也可以从 XML 数据源中进行访问。通过 XML,数据可供各种阅读设备使用(掌上计算机、语音设备、新闻阅读器等),还可以供盲人或其他残障人士使用。

  5. 用于创建新的互联网语言

    很多新的互联网语言是通过 XML 创建的。例如:

    • XHTML
    • 用于描述可用的 Web 服务 的 WSDL
    • 作为手持设备的标记语言的 WAP 和 WML
    • 用于新闻 feed 的 RSS 语言
    • 描述资本和本体的 RDF 和 OWL
    • 用于描述针对 Web 的多媒体 的 SMIL

XML的树结构

XML 文档必须包含根元素。该元素是所有其他元素的父元素。XML 文档中的元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端,所有的元素都可以有子元素,父、子以及同胞等术语用于描述元素之间的关系。父元素拥有子元素。相同层级上的子元素成为同胞(兄弟或姐妹)。所有的元素都可以有文本内容和属性(类似 HTML 中)。

XML树结构

<bookstore>
    <book category="COOKING">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
    <book category="CHILDREN">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
    <book category="WEB">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
    </book>
</bookstore>

实例中的根元素是 <bookstore>。文档中的所有 <book> 元素都被包含在 <bookstore> 中。<book> 元素有 4 个子元素:<title><author><year><price>

XML语法

  • XML 声明

    XML 声明文件的可选部分,如果存在需要放在文档的第一行第一列

    <?xml version="1.0" encoding="utf-8"?>
    

    version 该属性是必须存在的

    encoding 该属性不是必须的。打开当前xml文件的时候应该是使用什么字符编码表(一般取值都是UTF-8) 文档声明的字符编码必需和文档本身的编码一致

    standalone该属性不是必须的,描述XML文件是否依赖其他的xml文件,取值为yes/no

    以上实例包含 XML 版本( UTF-8 也是 HTML5, CSS, JavaScript, PHP, 和 SQL 的默认编码。

  • 根元素

    XML 必须包含根元素,它是所有其他元素的父元素。

    <?xml version="1.0" encoding="UTF-8"?>
    <note>
      <to>Tove</to>
      <from>Jani</from>
      <heading>Reminder</heading>
      <body>Don't forget me this weekend!</body>
    </note>
    
  • 关闭标签

    在 HTML 中,某些元素不必有一个关闭标签:

    <p>This is a paragraph.
    <br>
    

    在 XML 中,省略关闭标签是非法的。所有元素都必须有关闭标签:

    <p>This is a paragraph.</p>
    <br />
    
  • 属性值

    与 HTML 类似,XML 元素也可拥有属性(名称/值的对)。在 XML 中,XML 的属性值必须加引号。

    <note date="12/11/2007">
    <to>Tove</to>
    <from>Jani</from>
    </note>
    
  • 实体引用

    在 XML 中,一些字符拥有特殊的意义。例如把字符 “<” 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。在 XML 中,有 5 个预定义的实体引用:

    引用 被替代符号
    &lt; <
    &gt; >
    &amp; &
    &apos; '
    &quot; "

    :在 XML 中,只有字符 “<” 和 “&” 确实是非法的。大于号是合法的,但是也有实体引用,建议全部都用实体引用表示。

  • 注释

    在 XML 中编写注释的语法与 HTML 的语法很相似。

    <!-- This is a comment -->
    
  • 标签命名规则

    • 名称可以包含字母、数字以及其他的字符
    • 名称不能以数字或者标点符号开始
    • 名称不能以字母 xml(或者 XML、Xml 等等)开始
    • 名称不能包含空格
  • 标签的属性

    标准语法:<person id="1"></person> id是属性名,1表示属性值,不管是数值还是其他都要使用引号引起来

    属性位置:写在单标记中或者写在双标记的开始标记中

  • 注意事项

    1. XML 标签大小写敏感

      XML 标签对大小写敏感。标签 <Letter> 与标签 <letter> 是不同的。必须使用相同的大小写来编写打开标签和关闭标签。

      <!--由于大小写问题Message标签为被关闭-->
      <Message>这是错误的</message>
      <message>这是正确的</message>
      
    2. XML 可以嵌套使用,但是不可以交叉使用

      <!--错误的交叉使用-->
      <b><i>This text is bold and italic</b></i>
      <!--正确的嵌套使用-->
      <b><i>This text is bold and italic</i></b>
      
    3. XML 中的空格会被保留

      在 HTML 中会把多个连续的空格字符裁减(合并)为一个;在 XML 中,文档中的空格不会被删减。

    4. XML 以 LF 存储换行

      LF 换行即使用 \n 符号表示;还有一种换行 CR 换行,即用符号 \r 表示。

XML解析

DOM(Document Object Model)文档对象模型:就是把文档的各个组成部分看做成对应的对象。会把xml文件全部加载到内存,在内存中形成一个树形结构,再获取对应的值。

  • 常见解析工具:

    JAXP:SUN公司提供的一套XML的解析的API

    JDOM:开源组织提供了一套XML的解析的API-jdom

    DOM4J:开源组织提供了一套XML的解析的API-dom4j,全称:Dom For Java

    1. SAX解析

      一边解析一边操作,可以解析比较大的文件。但是不能对文件进行修改

    2. Dom解析

      • 将文件的所有内容读取到内存中形成DOM树,然后再解析。

      • 如果文件较大,影响性能。

      • CRUD操作都是可以的

    • 优点

      1. 大量使用了Java集合类,方便Java开发人员,同时提供一些提高性能的替代方法。
      2. 支持XPath。
      3. 有很好的性能。
    • 缺点:大量使用了接口,API较为复杂。

    pull:主要应用在Android手机端解析XML

dom4j使用方法

  1. 创建SaxReader对象

    SAXReader reader = new SAXReader();
    
  2. 设置命名空间 (如果XML使用约束且属性elementFormDefault值是:qualified,则必须要设置)

    HashMap<String, String> hashMap = new HashMap<String, String>();
    map.put("myKey", "自定义命名空间名");// key的名字自己取
    reader.getDocumentFactory().setXPathNamespaceURIs(map);
    
  3. SAXReader对象调用read方法,将当前XML文件,转换为Document对象

    // 获取字节流FileReader,用缓冲流包装一下BufferedReader
    Document document = reader.read(缓冲流);
    
  4. 获取根节点

    root = document.getRootElement();
    
  5. 通过父签添加子标签(元素),再给子标签添加值

    Element element = root.addElement("标签名");//返回值就是要添加的元素对象
    element.setText("标签值");
    
  6. 添加属性,获取属性对象、属性值

    // 给当前标签添加属性:xxx ,值是:xxx
    Element attribute = linkman.addAttribute("属性名","值");
    // 通过当前元素获取属性对象
    element.attribute("属性名");
    // 通过属性对象attribute获取属性值
    attribute.setText("值");
    // 通过属性对象attribute获取属性值
    String  = attribute.getText();
    
  7. 获取当前元素标签名与值

 ```java
 String name = e.getName();
 String text = e.getText();
 ```
  1. 获取子标签(元素)
 ```java
 // 获取指定名字的子标签(元素)
 当前标签.element(String name); 
 // 获取所有子标签(元素)
 当前标签.elements();
 ```
  1. 删除子元素,必须通过父元素 remove(子元素对象) 完成
 ```java
 父元素.remove(子元素对象); 
 ```
  1. 在dom4j里面提供了两个方法,用来支持xpath

    // 获取当前名字的多个节点
    selectNodes("xpath表达式"); 
    // 获取一个节点 
    selectSingleNode("xpath表达式"); 
    

    :在多层级的xpath使用的语法://命名空间:a[@id='b1']/命名空间:元素

案例

读取xml文件,删除、修改、新增节点

<?xml version="1.0" encoding="UTF-8"?>
<students>
	<student id="9527">
		<name>刘德华</name>
		<age>62</age>
		<address>中国香港</address>
	</student>
	<student id="13">
		<name>稻盛和夫</name>
		<age>90</age>
		<address>日本东京</address>
	</student>
	<student id="666">
		<name>梅西</name>
		<age>35</age>
		<address>阿根廷</address>
	</student>
</students>
public class XMLRead {
    public static void main(String[] args) {
        SAXReader reader = new SAXReader();
        ArrayList<Student> list = new ArrayList<>();
        try {
            Document doc = reader.read(new BufferedReader(new FileReader(new File("src/studyDemo/xmlTest/students.xml"))));
            Element root = doc.getRootElement();
            List<Element> rootElmts = root.elements();
            for (Element re:rootElmts) {
                Student student = new Student();
                student.setId(Integer.parseInt(re.attributeValue("id")));

                student.setName(re.element("name").getText());
                student.setAge(Integer.parseInt(re.element("age").getText()));
                student.setAddress(re.element("address").getText());
                list.add(student);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
public class XMLModify {
    public static void main(String[] args) {
        SAXReader reader = new SAXReader();
        try {
            // 读取XML文件
            Document doc = reader.read(new FileReader("src/studyDemo/xmlTest/newstudents.xml"));
            Element root = doc.getRootElement();
            // 在根节点下增加新的节点
            Element stuEle = root.addElement("student");
            stuEle.addAttribute("id", "991");
            Element nameEle = stuEle.addElement("name");
            nameEle.addText("木村拓哉");
            Element ageEle = stuEle.addElement("age");
            ageEle.addText("32");
            Element addEle = stuEle.addElement("address");
            addEle.addText("日本北海道");
            // 删除第二个节点
            root.elements().remove(1);
            // 修改第一个节点的文本内容
            Element stu0 = root.elements().get(0);
            Element age4stu0 = stu0.element("age");
            age4stu0.setText("64");
            
            // 将doc写入XML文件
            XMLWriter writer = new XMLWriter((new FileWriter("src/studyDemo/xmlTest/newstudents.xml")));
            writer.write(doc);
            writer.flush();


        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Xpath

XPath 是一门在 XML 文档中查找信息的语言。XPath 是 XSLT 中的主要元素。XQuery 和 XPointer 均构建于 XPath 表达式之上

<?xml version="1.0" encoding="UTF-8"?>
 <!--实例xml文档-->
<bookstore>
 
<book>
  <title lang="eng">Harry Potter</title>
  <price>29.99</price>
</book>
 
<book>
  <title lang="eng">Learning XML</title>
  <price>39.95</price>
</book>
 
</bookstore>

选取节点

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下面列出了最有用的路径表达式:

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取(取子节点)。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=‘eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]//title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

选取若干路径

通过在路径表达式中使用 | 运算符,可以选取若干个路径。

路径表达式 结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

XML约束

DTD约束

DTD 的目的是定义 XML 文档的结构。它使用一系列合法的元素来定义文档结构。

定义元素的格式:<!ELEMENT 元素名 元素类型>

XML-DTD约束

定义属性的格式:<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>

  • 属性的类型:

    CDATA类型:普通的字符串

  • 属性的约束:

    #REQUIRED 必须的

    #IMPLIED 属性不是必需的

    #FIXED value 属性值是固定的

引入DTD约束

  • 引入本地dtd

    <!--这是persondtd.dtd文件中的内容,已经提前写好-->
    <!ELEMENT persons (person)>
    <!ELEMENT person (name,age)>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT age (#PCDATA)>
    <!--在person1.xml文件中引入persondtd.dtd约束-->
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons SYSTEM 'persondtd.dtd'>
    <persons>
    	<person>
    		<name>张三</name>
    		<age>23</age>
    	</person>
    </persons>
    
  • 在xml文件内部引入

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons [
    	<!ELEMENT persons (person)>
    	<!ELEMENT person (name,age)>
    	<!ELEMENT name (#PCDATA)>
    	<!ELEMENT age (#PCDATA)>
    ]>
    <persons>
    	<person>
    		<name>张三</name>
    		<age>23</age>
    	</person>
    </persons>
    
  • 引入网络dtd

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons PUBLIC "dtd文件的名称" "dtd文档的URL">
    <persons>
    	<person>
    		<name>张三</name>
     		<age>23</age>
    	</person>
    </persons>
    

schema约束

schema和dtd的区别

  1. schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd
  2. 一个xml中可以引用多个schema约束文件,多个schema使用名称空间区分(名称空间类似于java包名)
  3. dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个数据类型
  4. schema 语法更加的复杂

schema约束

编写步骤

  1. 创建一个文件,这个文件的后缀名为.xsd。
  2. 定义文档声明
  3. schema文件的根标签为:<schema>
  4. <schema>中定义属性:xmlns=http://www.w3.org/2001/XMLSchema
  5. <schema>中定义属性 :targetNamespace = 唯一的url地址,指定当前这个schema文件的名称空间。
  6. <schema>中定义属性 :elementFormDefault="qualified",表示当前schema文件是一个质量良好的文件。
  7. 通过element定义元素
  8. 判断当前元素是简单元素还是复杂元素

schema约束规则

<?xml version="1.0" encoding="UTF-8" ?>
<schema
		xmlns="http://www.w3.org/2001/XMLSchema"
		targetNamespace="http://www.itsource.cn/javase"
		elementFormDefault="qualified"
>
	<!--定义persons复杂元素-->
	<element name="persons">
		<complexType>
			<sequence>
				<!--定义person复杂元素-->
				<element name = "person">
					<complexType>
						<sequence>
							<!--定义name和age简单元素-->
							<element name = "name" type = "string"></element>
							<element name = "age" type = "string"></element>
						</sequence>
						<!--定义属性,required( 必须的)/optional( 可选的)-->
						<attribute name="id" type="string" use="required"></attribute>
					</complexType>
				</element>
			</sequence>
		</complexType>
	</element>
</schema>

引入schema约束

  1. 在根标签上定义属性xmlns="http://www.w3.org/2001/XMLSchema-instance"

  2. 通过xmlns引入约束文件的名称空间

  3. 给某一个xmlns属性添加一个标识,用于区分不同的名称空间

    格式为: xmlns:标识="名称空间地址" ,标识可以是任意的,但是一般取值都是xsi

  4. 通过xsi:schemaLocation指定名称空间所对应的约束文件路径

    格式为:xsi:schemaLocation = "名称空间url 文件路径"

<?xml version="1.0" encoding="UTF-8" ?>
<persons
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns="http://www.itsource.cn/javase"
		xsi:schemaLocation="http://www.itsource.cn/javase person.xsd"
>
	<person id="001">
		<name>张三</name>
		<age>23</age>
	</person>
</persons>