XML 基础


xml(Extensive Markup Language 可扩展标记语言)

  • 作用
    1. 用来保存数据
    2. 用来做配置文件
    3. 数据传输载体

HTML注重于数据的显示,XML注重于数据的存储。

一、XML文档规则

1、文档声明
<?xml version="1.0" encoding="utf-8" standalone="no"?>

version: 解析该xml时,使用什么版本的解析器
encoding: 该文档的解码方式
standalone: 该文档是否关联其他文档

2、标签(元素)定义
  1. <> 括起来的元素,成对出现,如

  2. 文档声明下面的第一个标签称为根标签,有且仅有一个

  3. 空标签,既是开始标签也是结束标签,如

  4. 标签名可以自定义

    XML 命名规则:

    • 名称可以含字母、数字以及其他的字符
    • 名称不能以数字或者标点符号开始
    • 名称不能以字符 “xml”(或者 XML、Xml)开始
    • 名称不能包含空格
    • 尽量简单且见名知意
3、标签属性
  • 属性通常提供属于数据组成部分的信息,如果属性值里包含的信息属于该实体本身,则应该使用子元素来指定该信息,因此,W3C推荐尽量使用子元素,而避免使用属性
  • 定义在标签里面,<元素名称,属性名称=“属性值”> 内容</元素名称>
    ​ 如: <stu id=“1002”> 小明
4、xml注释

​ 与HTML类似,不允许放在文档第一行,必须放在文档声明下面
​ 如: <!–注释内容–>

5、实体与CDATA标记

​ 严格地讲,在 XML 中仅有字符 “<“和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。

实体引用所表示的符号
&lt;<
&amp;&
&gt;>
&apos;‘(英文单引号)
&quot;"(英文双引号)

​ 如果某段字符串里面有过多的字符,并且里面包含了类似标签或者关键字的这种文字,不想让xml的解析器去解析。那么可以使用CDATA来包装。不过这个CDATA一般比较少看到。通常在服务器给客户端返回数据的时候。

  • 语法

    <![CDATA[文本内容]]>

如:

<![CDATA[<a href=“http://www.baidu.com”>I Love My Home]]>

6、命名空间

​ 解决同名的标签名。

  • 语法:

xmlns[:prefix] = "命名空间字符串"

xmlns:bb="http://www.moc.com/teach"
xmlns:aa="http://www.moc.com/teach"

<aa:name></aa:name>
<bb: name></bb:name>	

二、XPath

​ XPath语言是一门专门用于在XML文档中查找信息的语言,其他XML程序可利用XPath在XML文档中对元素和属性进行导航。

  • 为什么要查找标签和属性?

XML文档是用来存储数据的,需要将数据提取出来使用,所以通过查找标签和属性进一步获取数据。

1、XPath节点
节点类型描述
XML文档根节点XML文档的根称为文档节点或根节点
元素节点一个元素的开始标签、结束标签,以及开始标签和结束标签之间的全部内容整体
属性节点元素的每个属性,属性节点包括属性名和属性值两个部分。属性节点必须依附于元素节点
注释节点文档中<!–和->包含的部分,注释对应的就是注释节点
命名空间节点代表文档中的xmlns:prefix属性
文本节点元素中间的字符数据,包括CDATA段中的字符数据
2、基本概念
  • 基本值(原子值)

    用于表示简单的数据值,例如整数值、字符串等。可以把基本值当成没有父节点且没有子节点的节点。

  • XPath2.0提出的一个术语,一个项代表一个节点或基本值。

  • 节点集和序列

    1. XPath1.0里将XPath表达式表示多个节点称为节点集
    2. XPath2.0提出的序列可以代表一个普通的项,也可以代表节点集
  • 节点关系

    1. 父节点
    2. 子节点
    3. 兄弟节点
    4. 祖先节点
    5. 后代节点
  • 相对路径和绝对路径

    绝对路径以斜线(/)开头,如/stu/小明/age

3、基础语法

​ XPath使用路径表达式来定位XML文档中的节点或节点集,每个Xpath表达式总由多个步(step)组成,多个步之间用斜线分隔

  • 格式:

轴::节点测试[ 限定谓语 ]


  • XPath的步使用轴来定义所选节点与当前节点之间的结构关系
轴名描述
ancestor祖先节点
ancestor-or-self祖先节点并包含自身
attribute选择节点的所有属性
child选取当前节点的所有子节点
parent选取当前节点的父节点
descendant当前节点的所有后代节点
descendant-or-self当前节点的所有后代节点并包含自身
self当前节点自身
following-sibling选择当前节点的兄弟节
  • 节点测试

    节点测试用于从指定轴所匹配的节点集中选出特定的节点。

节点测试名描述实例
nodename从轴匹配的所有节点中child:book选出具有nodename的节点child::student
node()选择指定轴匹配的所有类型节点child::node()
text()选择指定轴匹配的所有文本类型节点child::text()
comment()选择指定轴匹配的所有注释节点descendant::comment()
*通配符,不进地任何过滤child:*
  • 限定谓语

    限定谓语是一个boolean表达式,或者可以转换为boolean值的表达式, 用于进一步提炼所选的节点集。限定谓语应该放在括号中

    语法

child::student[1] 或 child::student[ positio()=1 ]

4、运算符和函数
  • 算术运算符

    +(加)、-(减)、*(乘)、div(除)、mod(求余)

  • 比较运算符

    =(等于)、!=(不等于)、<(小于)、<=(不大于)、>(大于)、>=(不小于)

  • 逻辑运算符

    or(或)、and(与)

  • 组合运算符 |

    可用于组合多个路径表达式,通过“I"运算符,一次选取若干个路径

    如: student[position() = 1] | name[position() = last() ]

  • 常见函数

    函数名描述
    fn:position()返回当前正在被处理的节点在父节点中的index值
    fn:last()返回当前正在被处理的节点列表中项的数目
    fn:name()返回当前节点的名称或指定节点集中第一个节点的名称
    fn:root()通常返回文档根节点

三、XML约束

下面的文档,属性的ID值是一样的。现实中是不可能出现的,并且第二个学生的姓名有好几个,一般也很少。那么怎么规定ID的值唯一,或者是元素只能出现一次,不能出现多次?这是需要该XML文档进行约束。

<stus>
	<stu id="18086">
		<name>张三</name>
		<age>18</age>
		<address>深圳</address>
	</stu>
	<stu id="18086">
		<name>李四</name>	
		<name>李五</name>
		<name>李六</name>
		<age>28</age>
		<address>北京</address>
	</stu>
</stus>
  1. DTD(文档类型定义)

    定义XML文档的合法构建模块。

    它使用一系列的合法元素来定义文档结构。
    语法自成一派,出现的早。可读性比较差。

  2. Schema
    XML Schema 语言也可作为 XSD(XML Schema Definition)来引用。
    其实就是一个xml,使用xml的语法规则,xml解析器解析起来比较方便,是为了替代DTD。
    但是Schema约束文本内容比DTD的内容还要多,所以目前也没有真正意义上的替代DTD。

1、DTD简介
  1. 引入外部的DTD
<!-- stus.dtd文件:-->
<!ELEMENT stus (stu, stu)>
<!ELEMENT stu (name, age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

<!-- stus.xml文件: -->
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--文档类型 根标签名称  网络上的dtd  dtd的名称 dtd的路径
<!DOCTYPE stus PUBLIC "//UNKNOWN/" "unknown.dtd"> -->
    
<!--文档类型 根标签名称  本地的dtd dtd的路径 -->
<!DOCTYPE stus SYSTEM  "stus.dtd">
<stus>
	<stu>
		<name>张三</name>
		<age>18</age>
	</stu>
	<stu>
		<name>李四</name>
		<age>16</age>
	</stu>
</stus>
  1. xml嵌入DTD
<!-- stus.xml文件:-->
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE stus [
	<!ELEMENT stus (stu, stu)>
	<!ELEMENT stu (name, age)>
	<!ELEMENT name (#PCDATA)>
	<!ELEMENT age (#PCDATA)>
]>
<stus>
	<stu>
		<name>张三</name>
		<age>18</age>
	</stu>
	<stu>
		<name>李四</name>
		<age>16</age>
	</stu>
</stus>
  1. DTD基本语法
<!-- stus.dtd文件:-->
<?xml version="1.0" encoding="utf-8" ?>
<!--声明元素 <!ELEMENT 元素名称 类别>  -->
<!ELEMENT stus (stu)+>       <!-- +:一个或多个  *:零个或多个 ?:零个或一个 -->
<!ELEMENT stu (name, age)>   <!-- stu下面有两个元素name,age;逗号(,): 顺序为name-age , |:表示任意一个-->
<!ELEMENT name (#PCDATA)>    <!-- (#PCDATA):name为包含内容的简单标签 -->
<!ELEMENT age (#PCDATA)>

<!--声明属性 <!ATTLIST 元素名称 属性名称 属性类型 默认值> -->
<!ATTLIST stu id CDATA #IMPLIED>  <!-- stu可以有属性id,其值的类型为CDATA, CDATA:字符数据 #IMPLIED:属性不是必需的 -->

<!--  <!ATTLIST stu id ID #REQUIRED>
	  ID: 值为唯一的 id
	  #REQUIRED: 属性值是必需的
	  ID 类型的属性必须为 #REQUIRED
	  id属性的值前加上"字母"或者_以符合XML命名规范再次验证则可通过
-->

<!-- stus.xml文件: -->
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE stus SYSTEM  "stus.dtd">
<stus>
	<stu id="c102">
		<name>张三</name>
		<age>18</age>
	</stu>
	<stu id="c1003">
		<name>李四</name>
		<age>16</age>
	</stu>
</stus>
2、 schema(xsd)简介
<!-- teacher.xsd文件:-->
<?xml version="1.0" encoding="utf-8" ?>

<!--   xmlns:  xml namespace 命名空间
	   targetNamespace: 目标名称空间。下面定义的那些元素都与这个名称空间绑定上
	   elementFormDefault: 元素的格式化情况
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.w3school.com.cn"
	elementFormDefault="qualified">
    
	<!-- 复杂元素 -->
	<element name="teachers">
		<complexType>  <!-- 声明复杂元素 -->
			<sequence maxOccurs="unbounded">  <!--包裹的标签可以重复任意次-->
				<!-- 复杂元素 -->
				<element name="teacher">
					<complexType>
						<sequence>
							<!--下面为简单元素 -->
							<element name="name" type="string"></element>
							<element name="age" type="int"></element>
						</sequence>
					</complexType>
				</element>
			</sequence>
		</complexType>
	</element>
</schema>

<!-- teacher.xml文件:-->
<?xml version="1.0" encoding="utf-8" ?>
<teachers
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.w3school.com.cn"
	xsi:schemaLocation="http://www.w3school.com.cn teacher.xsd">

	<teacher>
		<name>James</name>
		<age>28</age>
	</teacher>
	<teacher>
		<name>Danial</name>
		<age>27</age>
	</teacher>
</teachers>	

四、XML的解析

​ 就是获取元素里面的字符数据和属性数据,常用解析方式有如下两种:

  1. DOM (document object model)

    ​ 把整个xml全部读到内存当中,形成树状结构。整个文档称之为document对象,属性对应Attribute对象,所有的元素节点对应Element对象,文本也可以称之为Text对象,以上所有对象都可以称之为Node节点。如果xml特别大,那么将会造成内存溢出。可以对文档进行增删操作

  2. SAX (sample API for XML)
    基于事件驱动,读取一行解析一行,不会造成内存溢出。

1、JAXP

​ Java解析XML文档的API称为JAXP,它的全称是Java API for XML。

  • JAXP往往作为JDK的一部分发布,但它仅仅是一些API接口,并未提供真正的实现,因此实际使用过程中还需要具体的解析实现。

  • JAXP允许应用程序在不同的XML解析器之间切换

  • JAXP提供的与解析相关的类

DocumentBuilderFactory: 获取DOM解析工厂类
DocumentBuilder: DOM解析器标准接口
SAXParserFactory: 获取SAX解析器的工厂类
SAXParser: SAX解析器的标准接口

2、SAX解析XML
  • 流程

    解析XML文档时,SAX解析器负责在XML文档中”行走”,每当遇到文档开始、元素开始、文本、元素结束和文档结束时,都将负责向发送事件,而程序员则负责提供事件监听器来监听这些事件,并通过事件获取XML文档信息。

  • JAXP为SAX解析器提供的2组APl:

  1. XMLReader和XMLReaderFactory:XMLReaderFactory工厂类的createXMLReaderO静态方法用于创建XMLReader
  2. SAXParser和SAXParserFactory:SAXParserFactoryI厂类的newSAXParser()实例方法用于创建SAXParser(推荐)
  • SAXParser解析XML文档的方法:

    void parse(File f, DefaultHandler dh): 使用指定的dh作为监听器监听SAX解析事件,解析XML文档。

  • SAX解析事件

监听器描述
ContentHandler监听XML文档内容处理事件的监听器
DTDHandler监听DTD处理事件的监听器
EntityResolver监听实体处理事件的监听器
ErrorHandler监听解析错误的监听器

​ JAXP提供了一个DefaultHandler类,这个类实现了上述4个监听器接口,并为监听器接口中所包含的方法提供了空实现。

  • SAX解析XML文档步骤
  1. 在工程中引入Xerces-J具体解析器实现类 jar包 xml-apis.jar
  2. 自定义事件监听器继承自DefaultHandler
  3. 通过SAXParseFactory的newlnstance()方法创建SAX解析器工厂对象
  4. 通过SAXParseFactory对象的newSAXParser())方法创建SAXPasrer对象
  5. 调用SAXParser对象的parse()方法解析XML文档
public class SAXParse {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // 创建SAX解析器工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 创建SAX解析器
        SAXParser parser = factory.newSAXParser();
        // 开始解析XML文档
        parser.parse("C:\\Users\\Administrator\\Desktop\\1.xml", new mocHandler());
    }
}

// 具体解析方法
public class mocHandler extends DefaultHandler {
    // 定义一个变量来保存当前正在处理的tag
    private String currentTag;

    // 每当处理文本数据时将触发该方法
    @Override
    public void characters(char[] ch, int start, int lenght){
        String content = new String(ch, start, lenght);
        if(content.trim().length() > 0){
            System.out.println("<"+currentTag+">元素的值是:"+content.trim());
        }
    }

    // 每当文档解析结束时触发该方法
    @Override
    public void endDocument(){
        System.out.println("解析文档结束。");
    }

    // 解析元素结束时触发该方法
    @Override
    public void endElement(String uri, String localName, String qName){
        System.out.println("处理元素结束:"+qName);
    }

    // 解析文档开始时触发该方法
    @Override
    public void startDocument(){
        System.out.println("解析文档开始。");
    }

    //解析元素开始
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes){
        System.out.println("开始处理元素:"+qName);
        currentTag = qName;
        if(attributes.getLength() > 0){
            System.out.println("<"+ currentTag +">元素属性如下:");
            for (int i = 0; i < attributes.getLength(); i++) {
                System.out.println(attributes.getQName(i) + "---->" + attributes.getValue(i));
            }
        }
    }
}
  • SAX生成XML文档步骤
  1. 创建保存xml的结果流对象
  2. 获取sax生成工厂对象实例
  3. 获取sax生成处理者对象实例
  4. 获取sax生成器
  5. 生成文档及文档中的元素
public class BuildXML {
    public static void main(String[] args) throws TransformerConfigurationException, SAXException {
        // 创建保存XML的结果流对象
        Result resultXML = new StreamResult(new File("C:\\2.xml"));
        // 获取sax生成工厂实例
        SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        // 获取SAX生成处理者对象实例
        TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
        transformerHandler.setResult(resultXML);  // 保存xml的结果流对象
        // 获取SAX生成器
        Transformer transformer = transformerHandler.getTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 允许生成xml时生成额外的空格

        // 生成文档的开始
        transformerHandler.startDocument();
        AttributesImpl attributes = new AttributesImpl();
        AttributesImpl attrImpl = new AttributesImpl();
        attributes.addAttribute("", "", "语言", "", "中文");
        transformerHandler.startElement("", "", "书籍列表", attributes);

        // 第一本书
        transformerHandler.startElement("", "", "四大名著", attrImpl);

        transformerHandler.startElement("", "", "书名", attrImpl);
        transformerHandler.characters("红楼梦".toCharArray(), 0, "红楼梦".length());
        transformerHandler.endElement("", "", "书名");

        transformerHandler.startElement("", "", "作者", attrImpl);
        transformerHandler.characters("曹雪芹".toCharArray(), 0, "曹雪芹".length());
        transformerHandler.endElement("", "", "作者");

        transformerHandler.startElement("", "", "价格", attrImpl);
        transformerHandler.characters("85.00".toCharArray(), 0, "85.00".length());
        transformerHandler.endElement("", "", "价格");

        transformerHandler.endElement("", "", "四大名著");

        // 第二本书
        transformerHandler.startElement("", "", "四大名著", attrImpl);

        transformerHandler.startElement("", "", "书名", attrImpl);
        transformerHandler.characters("西游记".toCharArray(), 0, "西游记".length());
        transformerHandler.endElement("", "", "书名");

        transformerHandler.startElement("", "", "作者", attrImpl);
        transformerHandler.characters("罗贯中".toCharArray(), 0, "罗贯中".length());
        transformerHandler.endElement("", "", "作者");

        transformerHandler.startElement("", "", "价格", attrImpl);
        transformerHandler.characters("48.00".toCharArray(), 0, "48.00".length());
        transformerHandler.endElement("", "", "价格");

        transformerHandler.endElement("", "", "四大名著");

        transformerHandler.endElement("", "", "书籍列表");

        // 文档生成结束
        transformerHandler.endDocument();

        System.out.println("XML文档生成成功。");
    }
}
3、Dom4j解析XML

element.element(“stu”): 返回该元素下的第一个stu元素
element.elements(): 返回该元素下的所有子元素

  1. 创建SaxReader对象(需先导入dom4j-1.6.1.jar包)
  2. 指定解析的xml
  3. 获取根元素。
  4. 根据根元素获取子元素或者下面的子孙元素
try {
	// 1.创建sax读对象
	SAXReader reader = new SAXReader();
	// 2.指定解析XML的解析源
	Document document = reader.read(new File("D:\\stus.xml"));
	// 3. 得到元素
	Element rootElement = document.getRootElement();  // 获取根元素
	//System.out.println(rootElement.getName());
	Element ageElement = rootElement.element("stu").element("age"); // 获取根元素下的stu元素下的age元素
	//System.out.println(ageElement.getText());  // 获取标签的文本内容

	// 获取根元素所有的子元素
	List<Element> elements = rootElement.elements();
	for (Element element : elements) {
		String name = element.element("name").getText();
		String age = element.element("age").getText();
		String address = element.element("address").getText();
		System.out.println("name="+name+"---age="+age+"---address="+address);
	}
} catch (Exception e) {
	e.printStackTrace();
}

dom4j支持xpath的写法,能够快速的定位到具体的某一个元素

  1. 添加jar包依赖 jaxen-1.1-beta-6.jar
  2. 在查找指定节点的时候,根据xPath语法规则来查找
  3. 后续的代码与上一个的解析代码一样。
try {
	// 1.创建sax读对象
	SAXReader reader = new SAXReader();
	// 2.指定解析XML的解析源
	Document document = reader.read(new File("D:\\stus.xml"));
	// 3. 得到标签
	Element rootElement = document.getRootElement();  // 获取根元素

	// 使用Xpath,需添加支持的jar包jaxen-1.1-beta-6.jar, 下面参数为XPath表达式
	Element nameElement = (Element) rootElement.selectSingleNode("//name");
	System.out.println(nameElement.getText());

	System.out.println("--------------");
	// 获取文档里的所有元素
	List<Element> list = rootElement.selectNodes("//name");
	for (Element element : list) {
		System.out.println(element.getText());
	}

} catch (Exception e) {
	e.printStackTrace();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值