Extendsiable Markup Language(XML)

    最近学习了xml入门和解析, 为了加深理解特地整理了一下相关笔记.

1. HTML&XML
  • html和xml都属于SGML(标准通用标记语言)语言分支
  • 程序型标记-HTML(HTML5不属于SGML分支)
  • 描述型标记-XML(1998正式形成标准)
  • 两个都由W3C维护
2 . XML入门

 extendsiable markup language, 可扩展标记语言, xml只代表数据本身, 而不包含任何样式结构的呈现, 所以也称之为一种数据描述语言.

3 . XML作用
  • 实现不同平台之间的数据交换(webservice:soap协议)
  • xml还可以用于一些应用程序的配置文件(框架, tomcat, servlet)
4 . XML文档构成

一个标准的XML文档由3部分构成.
    1 . xml指令
    xml指令主要描述xml的版本(目前只有1.0), 编码, 文档类型定义是否是一个独立的文件.

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

    2 . 文档类型定义(通常可不加)
    文档类型定义(DTD,XSD): 规范文档中允许出现的标记, 属性, 以及标记之间的关系.

<!DOCTYPE>

    3 . 文档元素部分
    文档的详细构成: 标签, 属性, 文本.

  • xml元素: 由一对标签以及标签之间的内容构成.
  • xml标签: 主要包含开始标记以及结束标记.
  • xml属性: 通常定义在元素的开始标记中.
5 . XML规范

    XML规范相对HTML来说相当严格.
    1. 标记必须成对出现(除空标记,即单标签).
    2. 标签严格区分大小写.
    3. 属性值必须使用双引号""来包含.
    4. 属性值中不能包含特殊符号(<, &, …).
    5. xml支持类似html中实体(<(& lt;), >(& gt;), "(& quot;))
    6. 注释代码不允许嵌套
    7. 一个xml文档中有且只有一对根节点.

    元数据

<![CDATA[
			元数据具体内容.
]]>
<languges language="java">
   <code>
		<![CDATA[
		public static void main(String[] args)
		{
		}
		]]>
	</code>
</languges>

    命名空间: namespace, 防止标签命名冲突.

<h:table></h:table>
<f:table></f:table>
6 . JSON&XML

    AJAX: 异步的 javascript and XML
    JSON作用: 是一种轻量级的数据交换格式, 可以实现不同平台之间的数据交换.
    XML作用: 上面已述(第3条).

7. XML解析

1. DOM解析:
    将需要被解析的文档完整的加载到内存中(有大小限制, 无法解析大文件), 解析为一颗倒置的文档树, 可以通过解析器任意获取文档.
    优点: 适合解析较小的文档, 解析速度很快, 可以任意搜索节点, 并行搜索.
    缺点: 一次性加载整个文档,会消耗大量内存, 一般无法解析过大的文件(和内存有关).

package com.softeem.xml.parse;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ParseByDOM {

	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		
		//实例化一个解析工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		//获取解析器对象
		DocumentBuilder builder = factory.newDocumentBuilder();
		//解析文件并获取文档对象
		Document document = builder.parse(new File("src/userInfo.xml"));
		//根据元素的标签名获取元素并取出匹配第一个元素(获取文档根节点)
		Node root = document.getElementsByTagName("users").item(0);
		//获取当前节点下的所有子节点
		NodeList list = root.getChildNodes();
		for (int i = 0; i < list.getLength(); i++) {
			Node node = list.item(i);
			//判断当前节点名称是否为user
			if("user".equals(node.getNodeName())){
				//获取节点中的属性节点集合
				NamedNodeMap nnm = node.getAttributes();
				//根据节点名称(属性名)获取节点值(属性值)
				String id = nnm.getNamedItem("id").getNodeValue();
				String type = nnm.getNamedItem("type").getNodeValue();
				System.out.println(id);
				System.out.println(type);
				
				//继续搜索user节点下的子节点
				NodeList user_child_list = node.getChildNodes();
				for(int j=0;i<user_child_list.getLength();j++){
					Node c = user_child_list.item(j);
					if(c != null){
						if("name".equals(c.getNodeName())){
							String name = c.getTextContent();
							System.out.println("姓名:"+name);
						}else if("sex".equals(c.getNodeName())){
							String sex = c.getTextContent();
							System.out.println("性别:"+sex);
						}else if("age".equals(c.getNodeName())){
							String age = c.getTextContent();
							System.out.println("年龄:"+age);
						}else if("ismarray".equals(c.getNodeName())){
							String ismarray = c.getTextContent();
							System.out.println("婚否:"+ismarray);
						}
					}
				}
			}
		}
	}

}

    userInfo.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE users[ -->
<!-- 	<!ELEMENT users (user)> -->
<!-- 	<!ELEMENT user (name,sex,age,ismarray)> -->
<!-- 	<!ELEMENT name (#PCDATA)> -->
<!-- 	<!ELEMENT sex (#PCDATA)> -->
<!-- 	<!ELEMENT age (#PCDATA)> -->
<!-- 	<!ELEMENT ismarray (#PCDATA)> -->
<!-- 	<!ATTLIST user id(#CDATA)> -->
<!-- ]> -->
<users>
	<user id="201709001" type="admin">
		<name>二蛋</name>
		<sex></sex>
		<age>18</age>
		<ismarray>未婚</ismarray>
	</user>
</users>

2 . SAX解析:
    基于事件驱动的方式以类似流媒体的方式进行解析, 在读取到一部分后立即开始解析,直到读取到文档结束标记后停止解析.
    优点: 适合解析较大的文档, 解析效率较快, 一边读取一边解析.
    缺点: 无法任意的搜索节点, 比较难以实现并行搜索.
    使用方法: 该类要继承DefaultHandler, 之后重写5个方法(start/endDocument, characters, start/endElement).

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.softeem.xml.dto.Book;

public class ParseBySAX extends DefaultHandler{

	public List<Book> books;
	private Book book;
	private String nowTag;//记录当前读取的标记
	
	//文档开始时触发
	@Override
	public void startDocument() throws SAXException {
		System.out.println("开始解析");
		books = new ArrayList<Book>();
	}

	//读取到开始标记时触发
	/**
	 * @param uri			命名空间的uri地址
	 * @param localName		不带命名空间前缀的标签名称
	 * @param qName			包含命名空间的标签名	
	 * @param attributes    元素中的属性列表
	 */
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException {
		System.out.println("读取到开始标记:"+qName);
		//记录当前读取到的开始标记
		nowTag = qName;
		//当读取到一个开始的book标记后创建一个book对象
		if("book".equals(qName)){
			book = new Book();
			book.setNo(attr.getValue("no"));
		}
	}
	
	//读取到文本节点时触发
	@Override
	public void characters(char[] c, int start, int length) throws SAXException {
		System.out.println("读取到文本节点:"+new String(c,start,length));
		String value = new String(c,start,length);
		//根据当前记录的标记决定将文本值设置给对象的哪一个属性
		if("name".equals(nowTag)){
			book.setName(value);
		}else if("author".equals(nowTag)){
			book.setAuthor(value);
		}else if("price".equals(nowTag)){
			book.setPrice(value);
		}else if("publish".equals(nowTag)){
			book.setPublish(value);
		}
		//将节点置为空(重要)
		//nowTag = "";
	}
	
	//读取到结束标记时触发
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		System.out.println("读取到结束标记:"+qName);
		//判断是否读取到book结束
		if("book".equals(qName)){
			books.add(book);
		}
	}
	
	//文档结束时触发
	@Override
	public void endDocument() throws SAXException {
		System.out.println("解析完成");
	}

	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		//创建解析器工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//生产解析器
		SAXParser parse = factory.newSAXParser();
		
		ParseBySAX pbs = new ParseBySAX();
		//开始解析
		parse.parse("src/book.xml",pbs);
		
		List<Book> list = pbs.books;
		System.out.println(list);
	}
}

    book.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<books>
	<book no="0103410">
		<name>还珠格格</name>
		<author>琼瑶</author>
		<publish>芒果台出版社</publish>
		<price>34.50</price>
	</book>
	<book no="0810276">
		<name>神雕侠侣</name>
		<author>金庸</author>
		<publish>北京大学出版社</publish>
		<price>66.48</price>
	</book>
	<book no="0911239">
		<name>疯狂java讲义</name>
		<author>李刚</author>
		<publish>电子工业出版社</publish>
		<price>99.7</price>
	</book>
</books>

3. JDOM解析:
    java-base Document Object Model
    性能比较差, 但使用比较简单.
    使用方法:
    需要导入一个jar包(jdom.jar)

package com.softeem.xml.parse;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

/**
 * JDOM(Java-based Document Object Model)
 * @author mrchai
 */
public class ParseByJDOM {

	public static void main(String[] args) throws JDOMException, IOException {
		
		//创建解析器
		SAXBuilder builder = new SAXBuilder();
		//解析指定文档为一个Document对象
		Document document = builder.build(new File("src/book.xml"));
		//获取文档的根节点
		Element root = document.getRootElement();
		//获取根节点下所有的
		List<Element> list = root.getChildren("book");
		//遍历所有的book节点
		for (Element e : list) {
			//取出节点中指定属性值
			String no = e.getAttributeValue("no");
			//获取当前节点下指定名称的单个子节点,并去到节点中的文本值
			String name = e.getChild("name").getText();
			String author = e.getChild("author").getText();
			String publish = e.getChild("publish").getText();
			String price = e.getChild("price").getText();
			System.out.println(no);
			System.out.println(author);
			System.out.println(name);
			System.out.println(publish);
			System.out.println(price);
			System.out.println("============");
		}
	}
}

4. DOM4J解析:
    document object model for java.
    使用时需要导包: dom4j.jar
    支持Xpath技术: 快速搜索节点(很方便).
需要导包: jaxen.jar
    使用方法:

package com.softeem.xml.parse;

import java.io.File;
import java.util.List;

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

/**
 * dom4j:document object model for java
 * 
 * log4j
 * slf4j
 * pinyin4j
 * 
 * @author mrchai
 *
 */
public class ParseByDOM4J {

	public static void main(String[] args) throws DocumentException {
		
		//创建一个dom4j解析器
		SAXReader reader = new SAXReader();
		//解析文档
		Document document = reader.read(new File("src/book.xml"));
		//获取根节点
		Element root = document.getRootElement();
		//获取当前根节点下指定名称的子节点集合
		List<Element> list = root.elements("book");
		for (Element e : list) {
			//获取当前元素的no属性值
			String no = e.attributeValue("no");
			String name = e.element("name").getText();
			String author = e.element("author").getText();
			String price = e.element("price").getText();
			String publish = e.element("publish").getText();
			
			System.out.println(no);
			System.out.println(name);
			System.out.println(author);
			System.out.println(price);
			System.out.println(publish);
		}
	}
}

使用Xpath技术:

package com.softeem.xml.parse;

import java.io.File;
import java.util.List;

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

public class ParseByDOM4J_XPath {

	public static void main(String[] args) throws DocumentException {
		//获取解析器
		SAXReader reader = new SAXReader();
		//解析文件获取文档对象
		Document document = reader.read(new File("src/book.xml"));
		
		//快速搜索books/book/name节点
		List<Node> list = document.selectNodes("books/book/name");
		for (Node node : list) {
			String qname = node.getName();
			String name = node.getText();
			System.out.println(qname+"==="+name);
		}
		
		List<Node> list2 = document.selectNodes("books/book");
		for (Node node : list2) {
			//获取节点的指定属性值
			String no = node.valueOf("@no");
			System.out.println("--->"+no);
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值