XML学习总结
XML学习总结
xml的最先接触是学习Android时的activity_main.xml,在xml里写android布局,今天接触了JavaWeb的XML,记下一些心得和体验。
一、什么是XML
1、简单认识
XML ---Extensible Markup Language 可扩展标记语言 , 可配置文件、可网络传输。
看两个简单的图便可以理解
首先是一段简单的.xml代码
其DOM图
二、定义XML
1、简单声明
version: 解析这个xml的时候,使用什么版本的解析器解析
<?xml version="1.0" ?>
encoding: 解析xml中的文字的时候,使用什么编码来解析
<?xml version="1.0" encoding="UTF-8" ?>
standalone: no - 该文档会依赖关联其他文档,yes-- 这是一个独立的文档
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
2、简单语法
(1)、xml文档的后缀名 .xml
(2)、xml第一行必须定义为文档声明
(3)、xml文档中有且仅有一个根标签
(4)、属性值必须使用引号(单双都可)引起来
(5)、标签必须正确关闭
(6)、xml标签名称区分大小写
3、CDATA区
在该区域中的数据会被原样展示
格式: <![CDATA[ 数据 ]]>
三、约束
规定xml文档的书写规则(了解即可)
1、DTD约束
DTD一种简单的约束
DTD:
引入dtd文档到xml文档中
* 内部dtd:将约束规则定义在xml文档中
* 外部dtd:将约束的规则定义在外部的dtd文件中
* 本地:<!DOCTYPE 根标签名 SYSTEM "dtd文件的位置">
* 网络:<!DOCTYPE 根标签名 PUBLIC "dtd文件名字" "dtd文件的位置URL">
一个简单的例子
<!ELEMENT stus (stu)> : stus 下面有一个元素 stu , 但是只有一个
<!ELEMENT stu (name , age)> stu下面有两个元素 name ,age 顺序必须name-age
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST stu id CDATA #IMPLIED> stu有一个属性 文本类型, 该属性可有可无
元素的个数:
+ 一个或多个 例如:stus(stu+)
* 零个或多个
? 零个或一个
属性的类型定义:
CDATA : 属性是普通文字
ID : 属性的值必须唯一
<!ELEMENT stu (name , age)> 按照顺序来
<!ELEMENT stu (name | age)> 两个中只能包含一个子元素
2、Schema约束
Schema一种复杂的约束
Schema:
引入:
(1)、填写xml文档的根元素
(2)、引入xsi前缀. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
(3)、引入xsd文件命名空间. xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
(4)、为每一个xsd约束声明一个前缀,作为标识
xmlns="http://www.itcast.cn/xml"
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.itcast.cn/xml"
xsi:schemaLocation="http://www.itcast.cn/xml student.xsd">
这个认识一下,要注意一点: 一个xml 可以引用多个Schema约束,但是只能引用一个DTD约束。
四、解析
操作xml文档,将文档中的数据读取到内存中
1、解析的方式
(1)、DOM
DOM:将整个XML文件读取到内存,然后形成树状的结构。整个文档橙称之为document对象,每个元素称之为element对象,每个属性称之为attribute对象,以上所有的对象称之为Node节点。
* 优点:操作方便,可以对文档进行CRUD的所有操作
* 缺点:占内存
(2)、SAX
SAX:逐行读取,基于事件驱动的,读取一行,解析一行,不会造成内存溢出。
* 优点:不占内存。
* 缺点:只能读取,不能增删改
DOM解析 | SAX解析 |
---|---|
原理:一次性加载xml文档,不适合大容量文件读取 | 原理:加载一点,读取一点,处理一点。适合大容量 |
任意CRUD | 只能读取 |
任意读取任何位置的数据,甚至回读 | 只能从上向下,按顺序 |
DOM面向对象(Node,Element,Attribute) | 对于Java开发不太友好 |
2、几个常见的解析器
(1)、JAXP:sun公司提供的解析器,支持dom和sax两种思想
(2)、DOM4J:一款非常优秀的解析器
(3)、Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
(4)、PULL:Android操作系统内置的解析器,sax方式的。
3、导入解析包
因为以上常见的解析器需要导包,这里以IDEA为例子简要教一下。
(1)、导入需要的jar包
首先File->Project Structure->Modules->点击一旁的+号,添加你已经下载好jar包(可自行在网上下载)
(这里以Jsoup为例)
(2)、导出可执行的jar包
其次同样的界面里Artifacts->"+",选jar,选择from modules with dependencies,后有配置窗口出现,配置完成后,勾选include in project build >ok保存
(3)、 导出jar包
菜单:Build->build artfacts,导出jar包
完成解析包的导入,这时候我们就可以去import了
五、Jsoup解析教程
Jsoup是一款Java的HTML解析器,主要用来对HTML解析。 Jsoup中文文档
1、简单使用
对student.xml解析
分析步骤:
(1)、导入jar包
(2)、获取Document对象
(3)、获取对应的标签Element对象
(4)、获取数据
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JsoupDemo {
public static void main(String[] args) throws IOException {
//获取student.xml的path
String path =JsoupDemo.class.getClassLoader().getResource("student.xml").getPath();
//解析xml文档,加载文档进内存,获取dom树--->Document
Document document = Jsoup.parse(new File(path),"uft-8");
//获取元素对象 Element
Elements elements = document.getElementsByTag("name");
System.out.println(elements.size());
//获取第一个name的Element对象
Element e = elements.get(0);
//获取数据
String name = e.text();
System.out.println(name);
}
}
2、对象的使用
1. Jsoup:工具类,可以解析html或xml文档,返回Document
* parse:解析html或xml文档,返回Document
* parse(File in, String charsetName):解析xml或html文件的。
* parse(String html):解析xml或html字符串
* parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象
2. Document:文档对象。代表内存中的dom树
* 获取Element对象
* getElementById(String id):根据id属性值获取唯一的element对象
* getElementsByTag(String tagName):根据标签名称获取元素对象集合
* getElementsByAttribute(String key):根据属性名称获取元素对象集合
* getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合
3. Elements:元素Element对象的集合。可以当做 ArrayList<Element>来使用
4. Element:元素对象
1. 获取子元素对象
* getElementById(String id):根据id属性值获取唯一的element对象
* getElementsByTag(String tagName):根据标签名称获取元素对象集合
* getElementsByAttribute(String key):根据属性名称获取元素对象集合
* getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合
2. 获取属性值
* String attr(String key):根据属性名称获取属性值
3. 获取文本内容
* String text():获取文本内容
* String html():获取标签体的所有内容(包括字标签的字符串内容)
5. Node:节点对象
* 是Document和Element的父类
3、快捷查询方式
1. selector:选择器
* 使用的方法:Elements select(String cssQuery)
* 语法:参考Selector类中定义的语法
2. XPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言
* 使用Jsoup的Xpath需要额外导入jar包。
* 查询w3cshool参考手册,使用xpath的语法完成查询
仍对student.xml解析
package XML;
import cn.wanghaomiao.xpath.exception.XpathSyntaxErrorException;
import cn.wanghaomiao.xpath.model.JXDocument;
import cn.wanghaomiao.xpath.model.JXNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class JsoupDemo5 {
public static void main(String[] args) throws IOException, XpathSyntaxErrorException {
//获取student.xml的path
String path = JsoupDemo5.class.getClassLoader().getResource("student.xml").getPath();
//获取Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
//获取JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//xpath语法查询
//所有student标签
List<JXNode> jxNodes = jxDocument.selN("//student");
for (JXNode jxNode : jxNodes
) {
System.out.println(jxNode);
}
//查询所有student标签下的name标签
List<JXNode> jxNodes2 = jxDocument.selN("//student/name");
for (JXNode jxNode : jxNodes2) {
System.out.println(jxNode);
}
//查询student标签下带有id属性的name标签
List<JXNode> jxNodes3 = jxDocument.selN("//student/name[@id]");
for (JXNode jxNode : jxNodes3) {
System.out.println(jxNode);
}
//查询student标签下带有id属性的name标签 并且id属性值为IT
List<JXNode> jxNodes4 = jxDocument.selN("//student/name[@id='IT']");
for (JXNode jxNode : jxNodes4) {
System.out.println(jxNode);
}
}
}
六、一些高端玩法
这些都是在网上看的,不会违法吧emmmm,仅限娱乐,玩玩就好~
1、采集开源中国项目信息
package XML;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) throws IOException {
// write your code here
Set<String> setUrls = new HashSet<>();
for(int i = 1; i <= 5; i++)
{
String strUrl = "https://www.oschina.net/project/list?company=0&sort=score&lang=0&recommend=false&p=="+i;
setUrls.add(strUrl);
}
Set<String> setProjUrls = new HashSet<>();
for(String stringUrl : setUrls)
{
Document document = Jsoup.connect(stringUrl)
.userAgent("Mozilla/5.0 (Windows NT 6.1; rv:30.0) Gecko/20100101 Firefox/30.0")
.get();
System.out.println(document);
Elements elements = document.select("div.box.item");
for(Element element : elements)
{
Elements eleUrl = element.select("div.box-aw a");
String strPrjUrl = eleUrl.attr("href");
setProjUrls.add(strPrjUrl);
System.out.println(strPrjUrl);
Elements eleTitle = eleUrl.select(".title");
String strTitle = eleTitle.text();
System.out.println(strTitle);
Elements eleSummary = eleUrl.select(".summary");
String strSummary = eleSummary.text();
System.out.println(strSummary);
}
}
for(String stringUrl : setProjUrls)
{
Document document = Jsoup.connect(stringUrl)
.userAgent("Mozilla/5.0 (Windows NT 6.1; rv:30.0) Gecko/20100101 Firefox/30.0")
.get();
Elements elements = document.select("div.box-aw a h1");
String strTitle = elements.text();
System.out.println("标题:" + strTitle);
Elements elementsSection = document.select("section.list");
int nSize = elementsSection.get(0).children().size();
if(nSize == 0)
continue;
Element elementProtocol = elementsSection.get(0).child(0);
Elements elesPro = elementProtocol.select("span");
String strPro = elesPro.text();
System.out.println("开源协议:" + strPro);
nSize--;
if(nSize == 0)
continue;
Element elementLan = elementsSection.get(0).child(1);
Elements elesLan = elementLan.select("span").get(0).children();
StringBuilder strlan = new StringBuilder();
for(Element ele : elesLan)
{
String strLanTemp = ele.text();
if(strLanTemp.indexOf("查看源码")>=0)
break;
strlan.append(strLanTemp+",");
}
if(elesLan.size()>0)
{
String strLanguage = strlan.toString().substring(0,strlan.length()-1);
System.out.println("开发语言:" + strLanguage);
}
nSize--;
if(nSize == 0)
continue;
Element elementOS = elementsSection.get(0).child(2);
Elements elesOS = elementOS.select("span");
String strOS = elesOS.text();
System.out.println("操作系统:" + strOS);
nSize--;
if(nSize == 0)
continue;
Element elementAuthor = elementsSection.get(0).child(3);
Elements elesAuthor = elementAuthor.select("a.link");
String strAuthor= elesAuthor.text();
System.out.println("软件作者;" + strAuthor);
System.out.println("---------------------");
}
}
}
2、爬取腾讯首页全部图片
package XML;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
public class Main{
/**
* 下载图片到指定目录
*
* @param filePath 文件路径
* @param imgUrl 图片URL
*/
public static void downImages(String filePath, String imgUrl) {
// 若指定文件夹没有,则先创建
File dir = new File(filePath);
if (!dir.exists()) {
dir.mkdirs();
}
// 截取图片文件名
String fileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1, imgUrl.length());
try {
// 文件名里面可能有中文或者空格,所以这里要进行处理。但空格又会被URLEncoder转义为加号
String urlTail = URLEncoder.encode(fileName, "UTF-8");
// 因此要将加号转化为UTF-8格式的%20
imgUrl = imgUrl.substring(0, imgUrl.lastIndexOf('/') + 1) + urlTail.replaceAll("\\+", "\\%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 写出的路径
File file = new File(filePath + File.separator + fileName);
try {
// 获取图片URL
URL url = new URL(imgUrl);
// 获得连接
URLConnection connection = url.openConnection();
// 设置10秒的相应时间
connection.setConnectTimeout(10 * 1000);
// 获得输入流
InputStream in = connection.getInputStream();
// 获得输出流
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
// 构建缓冲区
byte[] buf = new byte[1024];
int size;
// 写入到文件
while (-1 != (size = in.read(buf))) {
out.write(buf, 0, size);
}
out.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 利用Jsoup获得连接
Connection connect = Jsoup.connect("http://www.qq.com");
try {
// 得到Document对象
Document document = connect.get();
// 查找所有img标签
Elements imgs = document.getElementsByTag("img");
System.out.println("共检测到下列图片URL:");
System.out.println("开始下载");
// 遍历img标签并获得src的属性
for (Element element : imgs) {
//获取每个img标签URL "abs:"表示绝对路径
String imgSrc = element.attr("abs:src");
// 打印URL
System.out.println(imgSrc);
//下载图片到本地
Main2.downImages("d:/img", imgSrc);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、采集悟空问答某问题的评论
哪些电视剧小时候看时觉得很经典,现在看却质疑剧的三观?为什么?
package XML;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
public class Main {
public static void main(String[] args) {
// 利用Jsoup获得连接
Connection connect=Jsoup.connect("https://www.wukong.com/question/6677402779574599943/");
try {
// 得到Document对象
Document document = connect.get();
Elements elements = document.select(".question-name");
System.out.println(elements.get(0).text());
Elements elements2 = document.select(".answer-item");
for(Element element : elements2)
{
Elements elements3 = element.select(".answer-user-avatar img");
System.out.println(elements3.attr("abs:src"));
elements3 = element.select(".answer-user-name");
System.out.println(elements3.text());
elements3 = element.select(".answer-user-tag");
System.out.println(elements3.text());
elements3 = element.select(".answer-text");
System.out.println(elements3.text());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}