1. XML概述
1.1 XML的概念
- HTML:Hyper Text Markup Language 超文本标记语言,由各种标签组成。
- XML: eXtensible Markup Language 可扩展标记语言
名词解释:
- 可拓展: 标签名可以自定义。
- 标记语言: 这门语言完全由标签构成的。
1.2 XML的作用
- 描述数据之间的关系。
- 用于不同系统之间的数据传输
1.3 XML 与HTML 的主要差异
区别 | HTML | XML |
---|---|---|
功能 | 制作网页,主要用于表示层 | 用于配置文件,传递数据 |
大小写 | 不区分大小写<br> 或<BR> | 区分大小写,<abc> 或<ABC> 是不同的 |
语法严谨 | 不严谨,如果一个标签有开头,没有结尾。 浏览器也可以解析。 | 严谨,标签开头和结尾必须严格配对 |
可扩展性 | 没有可扩展性,所有的标签都是固定好, 每个标签的功能固定。 | 所有的标签都是人为创造的,可以扩展。 |
2. XML文件组成
2.1 XML文件的组成元素
- 文档声明
- 标签元素Element
- 属性Attribute
- 注释Comment
- 转义字符(实体字符)
- 字符数据区(用于显示大量的特殊字符的时候)
- 处理指令(不常用)
2.2 文档声明
声明:<?xml version="1.0" encoding="UTF-8" ?>
格式: 以<?xml
开头,以?>
结尾
位置:必须出现在XML 文件的第1 行
2.2.1 文档声明的三个属性
- version: 用于指定XML 使用哪个版本,固定的写法1.0
- enconding :指定当前XML 编码
- standalone: yes/no 默认是yes,这个XML 文件是否是一个单独的文档
2.3 标签元素Element
- 语法:
<
开头,>
结尾, 中间是标签名; - 主体部分:分为有主体和无主体标签,主体部分可以包含文本或其它的子元素;
- 空元素:无主体标签也必须要关闭;
- 命名:不能有空格,不能有冒号,数字不能开头;
- 根元素:每个XML 文档必须有且只有一个根元素
2.4 属性Attribute
- 属性位置:必须放在开始标签中;
- 属性的值:必须使用单引号或双引号引起来;
- 在同一个标签中不能同时出现多个同名的属性;
- 命名中不能出现空格和冒号
2.5 注释Comment
<!--注释内容-->
- 注意:不可嵌套
2.6 转义字符(实体字符)
特殊字符需要转义才能显示,常用的有
特殊字符 | 转义字符 |
---|---|
< | < |
> | > |
“ | " |
‘ | ' |
& | & |
空格 | |
2.7 字符数据区
字符区的内容xml 文件的解释器在解释的时候,全部的内容都会当成普通的文本处理,即使遇到了特殊的符号也会只当成普通的文本去处理。
格式:
<![CDATA[ 文本数据 ]]>
- 定义:不由XML 解析器进行解析的纯文本数据
- 不可嵌套
2.8 处理指令
处理指令,简称PI(Processing instruction)用来指挥解析引擎如何解析XML 文档内容。
格式:
<?xml-stylesheet
开头,?>
结尾eg:
`<?xml-stylesheet type="text/css" href="文件名.css"?>
3. XML文件的约束
- 作用:用于限制xml文件出现的元素范围
xml约束文件分类:
- DTD 约束
- Schema 约束
一般不需要编写约束,直接引入已编写完
3.1 DTD约束
3.1.1 概念
- 定义:Document Type Definition 文档类型定义
- 作用:用来约束XML 文件的,它本身是一个文本文件
3.1.2 导入格式
导入DTD文件方式 | 描述 |
---|---|
<!DOCTYPE 根元素SYSTEM "DTD 文件"> | 系统的DTD 文件,使用范围比较小,一般用于公司,不对外开放的DTD 文件 |
<!DOCTYPE 根元素PUBLIC "DTD 文件"> | 公共的DTD 文件,用于互联网上,使用广泛的用途 |
<!DOCTYPE 根元素[dtd 文件的元素]> | xml 文件与dtd 文件混合在一起。 |
3.1.3 DTD文件写法(理解)
基本写法如下
<!ELEMENT 书架 (书+)> <!--根元素,包含1个或多个子元素-->
<!ELEMENT 书 (书名,作者,售价)> <!--子元素内包含三个子元素-->
<!ELEMENT 书名 (#PCDATA)> <!--PCDATA指文本-->
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
导入方法1
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "bookshelf.dtd"><!--写法1,使用<!DOCTYPE 根元素SYSTEM "DTD 文件">-->
<书架>
<书>
<书名>哈利波特</书名>
<作者>JK罗琳</作者>
<售价>49.9</售价>
</书>
</书架>
导入方法2
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 [<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>]><!--写法2,使用<!DOCTYPE 根元素 [dtd文件内容]>-->
<书架>
<书>
<书名>哈利波特</书名>
<作者>JK罗琳</作者>
<售价>49.9</售价>
</书>
</书架>
3.6 Schema约束
xml不能判断较多的数据类型,功能比较简单
而Schema功能更加强大,数据类型约束更完善,可取代DTD
3.6.1 Schema约束的使用
新建schema 约束文件(固定格式)
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="名称空间" elementFormDefault="qualified"> <xs:element name='根元素' > <xs:complexType> <xs:sequence maxOccurs='unbounded' > <xs:element name='子元素' > <xs:complexType> <xs:sequence> <xs:element name='子元素下的子元素1' type='xs:string' /> <xs:element name='子元素下的子元素2' type='xs:string' /> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
使用schema文件创建xml文件:
<根元素 xmlns="名称空间" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="名称空间 xsd约束文件名"> </根元素>
注意事项
- 名称空间(targetNamespace): 任何schema 文件都有一个名称空间,schema 名称空间是一个xsd 文件的唯一标记。相当于一个id 号,引入的时候必须要使用名称空间进行引入。
- 一般工程不需要自行编写schema文件,只需要根据相关的约束文件编写所需的xml文件即可
3.6.2 示例代码
xsd文件:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.baidu.com" <!--名称空间-->
elementFormDefault="qualified">
<xs:element name='书架' >
<xs:complexType>
<xs:sequence maxOccurs='unbounded' >
<xs:element name='书' >
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string' />
<xs:element name='作者' type='xs:string' />
<xs:element name='售价' type='xs:double' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<书架 xmlns="http://www.baidu.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.baidu.com books.xsd">
<书>
<书名>哈利波特</书名>
<作者>JK罗琳</作者>
<售价>49.9</售价>
</书>
</书架>
4. XML解析技术概述(重要)
4.1 XML解析的概述
- 对xml文件解析,读取其中的数据
4.2 解析方式和解析器
4.2.1 三种解析方式
4.2.1.1 DOM
- DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象
- 优点:元素与元素之间保留了结构关系,可以进行增删改查操作。
- 缺点:因为整个XML文档被加载到内存中,如果XML过大,可能出现内存溢出
4.2.1.2 SAX
- SAX:一种速度更快,更有效的方法。逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都触发对应的事件
- 优点:处理速度快,可以处理大文件。
- 缺点:只能读,逐行后将释放资源,解析操作繁琐。
4.2.1.3 PULL
- Android内置的XML解析方式,原理与SAX相同
4.3 DOM常见的解析开发包
JAXP:Oracle公司提供支持DOM和SAX开发包
Dom4j:比较简单的的解析开发包,将整个XML加载到内存中做为一棵DOM树。
JDom:与Dom4j类似
Jsoup:功能强大DOM方式的XML解析开发包,同时对HTML解析也很方便。
5. Jsoup的基本使用(重要)
- Jsoup是一款Java 的XML解析器,可直接解析某个URL地址、HTML文本内容和已经存在的文件。
- Jsoup它提供了一套非常省力的API,可通过DOM,CSS以及类似于CSS选择器的操作方法来取出和操作数据。
5.1 DOM解析原理
- 与HTML的DOM编程相同。XML的DOM会将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作。
- 与HTML相同,每个元素、属性和文本都是节点,类型为Node。而元素具有独有的类型:Element。注意,Element是Node的子类。
5.2 获取Document文档对象三种方式
由于所有节点都封装到Document对象中,只要获得Document对象,就可以获取xml的所有节点
5.2.1 利用html代码获得(不常用)
- static Document parse(String html);
->将该html内容转换为一个document对象。
->参数String html是整个html文件的内容
☞如果html内容太多,使用该方式将非常不方便,一般很少使用
5.2.2 利用file文件获得
- static Document parse(File file,"码表");
根据本地的资源文件生成document对象
5.2.2.1 步骤及注意事项
- 资源文件要求必须置于本模块的src目录下;
- 通过Class对象获得类路径,Class对象可以任意;
- 使用Class对象的
getResource()
方法获得类路径,类路径必须以/开头(可理解为当前src目录); - 使用
getPath()
方法获得类路径对应字符串,并据此创建File对象; - 根据File对象获得Document对象
5.2.2.2相关方法
- URL getResource("/xml文件名");
根据文件名路径获得文件资源URL对象;
- String getPath();
获得URL对象的真实路径
5.2.2.3示例代码
public class Demo02 {
public static void main(String[] args) throws IOException {
//获得类路径
String path = Demo02.class.getResource("/person.xml").getPath();
//创建File对象
File file = new File(path);
//生成document对象。
Document document = Jsoup.parse(file, "UTF-8");
System.out.println(document);
}
}
5.2.3 利用url获取Document对象
- static org.jsoup.Connection connect(String url);
通过URL字符串创建连接对象
- Document get(); 通过连接对象返回一个Document对象
5.2.3.1 步骤
- 定义一个具体html网页的url;
- 调用connect()方法,创建一个连接对象;
- 调用连接对象的get()方法,获得Document对象
5.2.3.2 示例代码
public class Demo03 {
public static void main(String[] args) throws IOException {
//根据指定url获得Connection对象
Connection connection = Jsoup.connect("http://baidu.com");
//根据连接对象获得Document对象
Document document = connection.get();
System.out.println(document);
}
}
5.3 根据标签属性获得节点
返回类型 | Document对象的方法 | 说明 |
---|---|---|
Element | getElementById(String id) | 通过id得到唯一元素对象 |
Element*s* | getElementsByTag(String tagName) | 通过标签名得到一组元素 |
Element*s* | getElementsByClass(String className) | 通过类名得到一组元素对象 |
5.3.1 示例代码
public class Demo01 {
public static void main(String[] args) throws IOException {
//获得Document对象
Document document = Jsoup.parse(new File(Demo01.class.getResource("/index.html").getPath()),"utf-8" );
//1.获取index.html中元素属性id="header"的一个元素并打印输出
Element element = document.getElementById("header");
System.out.println(element);
System.out.println("---------");
//2.获取index.html中所有h2标签名称的元素列表并打印输出
Elements elements = document.getElementsByTag("h2");
elements.forEach(System.out::print);
System.out.println("---------");
//3.获取index.html中所有元素含有class属性值为fl并打印输出
elements = document.getElementsByClass("fl");
elements.forEach(System.out::print);
}
}
5.4 根据css选择器获得节点(元素)
5.4.1 css选择器相关方法
返回类型 | 方法 | 说明 |
---|---|---|
Elements | select(String cssQuery) | 作用:通过选择器得到多个元素 |
Element | selectFirst(String cssQuery) | 作用:通过选择器得到第一个元素 |
其中,String cssQuery
指css选择器:
选择器类型 | 选择器语法 |
---|---|
ID选择器 | #id |
class选择器 | .类名 |
标签选择器 | 标签名 |
属性选择器(属性名) | [属性名] |
属性选择器(属性值) | [属性名=属性值] |
5.4.2 示例代码
public class Demo02 {
public static void main(String[] args) throws IOException {
//获得Document对象
Document document = Jsoup.parse(new File(Demo02.class.getResource("/index.html").getPath()), "utf-8");
//1.获取id="footer"元素并输出元素名称
Elements elements = document.select("#footer");
print(elements);
System.out.println("---------");
//2.获取index.html中所有元素含有class属性值为item并打印输出元素体内容
elements = document.select(".item");
print(elements);
System.out.println("---------");
//3.获取index.html中所有h3标签名称的元素列表并打印输出元素名称
elements = document.select(".item");
print(elements);
System.out.println("---------");
//4.获取index.html中含有属性data-toggle所有元素并打印输出元素名称和元素体数据
elements = document.select("[data-toggle]");
print(elements);
System.out.println("---------");
//5.获取index.html中属性role值为"tablist"的所有元素列表并打印输出元素名称
elements = document.select("[role=tablist]");
print(elements);
}
private static void print(Elements elements) {
elements.forEach(System.out::print);
}
}
5.5 组合选择器
选择器代码 | 说明 |
---|---|
标签名.类名 | 交集选择器,同时指定标签名和类名的选择器 |
标签名[属性名] | 得到某标签,包含指定属性的标签。 |
父元素 子元素 | 层级选择器,找某个元素下的所有子元素,选择器之间使用空格隔开 |
兄弟A+兄弟B | 查找在A元素后面第一个同级元素B |
5.5.1 示例代码
public class Demo03 {
public static void main(String[] args) throws IOException {
//获得Document对象
Document document = Jsoup.parse(new File(Demo03.class.getResource("/index.html").getPath()), "utf-8");
//1.获取index.html中div元素类名为item的元素,并打印元素数据
Elements elements = document.select("div.item");
elements.forEach(System.out::print);
System.out.println();
System.out.println("==============================");
//2.获取index.html中a元素含有属性data-toggle的所有元素列表并打印元素数据
elements = document.select("a[data-toggle]");
elements.forEach(System.out::print);
System.out.println();
System.out.println("==============================");
//3.获取index.html中属性id值为"banner"的所有div子元素并打印元素数据
elements = document.select("#banner div");
elements.forEach(System.out::print);
System.out.println();
System.out.println("==============================");
//4.获取index.html中class="navitem"元素后面同级第一个兄弟section元素并打印元素数据
elements = document.select(".navitem+section");
elements.forEach(System.out::print);
}
}
5.6 补充Element元素相关方法
Element对象的方法 | 说明 |
---|---|
String attr(“属性名”) | 得到元素指定属性的值 |
Elements children() | 得到当前元素所有的子元素,返回集合 |
String tagName() | 得到元素的标签名字 |
String text() | 得到元素主体内容中的文本 |
5.6.1 示例代码
需求:已有xml保存书的信息,已有一个对应的类Book(String category, String title, String author, int year, double price),使用DOM解析xml,封装成List,并且输出封装好的集合
准备xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
<book category="CHILDREN">
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
Book类代码省略
main代码如下:
public class Demo03 {
public static void main(String[] args) throws IOException {
//获得Document对象
Document document = Jsoup.parse(new File(Demo03.class.getResource("/books.xml").getPath()), "utf-8");
//使用dom解析
Elements books = document.select("book");
//创建List存放book对象
List<Book> bookList = new ArrayList<>();
//遍历books获得每个元素
for (Element element : books) {
//创建对象
Book book = new Book();
//获得属性值
String category = element.attr("category");
book.setCategory(category);
//获得element的所有子元素
Elements children = element.children();
//遍历children
for (Element child : children) {
//获得每个子元素的tagName和text,然后进行判断赋值
String tagName = child.tagName();
String text = child.text();
if ("title".equalsIgnoreCase(tagName)) {
book.setTitle(text);
} else if ("author".equalsIgnoreCase(tagName)) {
book.setAuthor(text);
} else if ("year".equalsIgnoreCase(tagName)) {
book.setYear(Integer.parseInt(text));
} else if ("price".equalsIgnoreCase(tagName)) {
book.setPrice(Double.parseDouble(text));
}
}
//每循环一次就给bookList添加元素
bookList.add(book);
}
//输出bookList
for (Book book : bookList) {
System.out.println(book);
}
}
}
6. xPath表达式
6.1 概念
- JsoupXpath 是一款纯Java开发的使用xpath解析HTML的解析器,JsoupXpath不是jsoup的一部分,是在jsoup基础上进行的扩展。
- XPath 使用路径表达式来选取HTML或XML文档中的元素节点或属性节点。
6.1.1使用步骤
导包—>写xPath表达式
6.1.2四种XPath语法方式:
1)绝对路径
2)相对路径
3)全文搜索
4)条件筛选
6.2 核心API方法
6.2.1 获得核心类JXDocument
方法 | 说明 |
---|---|
public JXDocument(Document doc) | 通过构造方法创建JXDocument对象 参数:org.jsoup.nodes.Document对象 |
List selN(String xpath) | 通过xpath表达式得到指定的节点对象JXNode 返回一个节点集合 |
JXNode selNOne(String xpath) | 通过xpath表达式得到符合条件的节点对象,返回一个节点 节点:包含属性Attribute或元素Element |
selN()相当于css选择器获得元素的select(),selNOne相当于css选择器获得元素的selectFirst()
6.2.2 节点JXNode的API
方法 | 说明 |
---|---|
Element getElement() | 通过节点得到它的元素 |
List sel(String xpath) | 用在相对路径上,从当前节点开始向下查询其它的子节点 |
6.3 绝对路径
6.3.1 语法
- 绝对路径必须从根元素开始写路径,所以必须以
/
开头,/
代表了根标签; - 绝对路径找节点绝对不能跳级 去寻找(即不能跳过路径下所有父元素);
- 路径中不能出现标签
6.2.2 示例代码
public class Demo01 {
public static void main(String[] args) throws XpathSyntaxErrorException, IOException {
Document document = Jsoup.parse(new File(Demo01.class.getResource("/index.html").getPath()),"utf-8" );
//使用Document对象获得对应的额JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//需求1: 采用绝对路径获取从根节点开始逐层的/body/div/ul/li节点列表并打印信息
List<JXNode> jxNodes = jxDocument.selN("/body/div/ul/li");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
//需求2: 找到head里面link标签
jxNodes = jxDocument.selN("/head/link");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
}
}
6.4 相对路径
6.4.1 语法
- 相对路径指的是相对于当前的路径,相对路径找节点就是相对于当前的路径找到需要的节点
- 所以需要判断执行sel()查找节点的是哪个对象
格式 | 说明 |
---|---|
子元素/孙元素 | 相对当前路径元素里面的子元素的选取 |
./子元素/孙元素 | 功能与上面的写法一样 . 表示当前路径 |
/子元素/孙元素 | 相对当前节点元素位置继续查找节点,需要使用JXNode.sel(xpath)的方法执行相对路径表达式。 |
其实上面三种是等价的,最常用的是第一种
注意事项
- 使用相对路径前需要用绝对路径获得当前的对象,此时xpath的
/
不可省略!! - 当前对象使用相对路径sel()时,xpath才可以省略
.
以及/
6.4.2 特殊的方法
- 相对路径对比其余三种方式有特有的方法获取元素:
sel()
6.4.3 示例代码
public class Demo02 {
public static void main(String[] args) throws XpathSyntaxErrorException, IOException {
//需求:先采用绝对路径获取body节点,再采用相对路径获取下一级div节点列表并打印信息
//获得JXDocument对象
JXDocument jxDocument = new JXDocument(Jsoup.parse(new File(
Demo02.class.getResource("/index.html").getPath()), "utf-8"));
//使用绝对路径获得当前的元素(body)
JXNode body = jxDocument.selNOne("/body"); //中间的“/”不可省略
//根据相对路径获得下一级的div节点
List<JXNode> jxNodes = body.sel("div");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
}
}
6.5 全局搜索
6.5.1 全文搜索获得不同节点语法
获取类型 | 语法代码 |
---|---|
获取元素节点 | 元素名 |
获取属性节点 | @属性名 |
6.5.2 全文搜索语法
格式 | 说明 |
---|---|
//子元素//元素或@属性(基本格式) | “//”符号,不用逐级写路径,可以直接选取到对应的节点,全文搜索匹配不需要按照逐层级写。 |
例子:
示例 | 含义 |
---|---|
//li | 全文搜索所有的li元素列表,不论li在哪一级元素 |
//div/a/img | 全文搜索所有的div,再逐层级搜索下面的a标签下的img元素 |
//link/@href | 全文搜索link元素,得到它的href属性,属性名前加@符号(注意在@前不要漏了/ !) |
6.5.3 示例代码
public class Demo03 {
public static void main(String[] args) throws XpathSyntaxErrorException, IOException {
Document document = Jsoup.parse(new File(Demo03.class.getResource("/index.html").getPath()),"utf-8" );
//使用Document对象获得对应的额JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//需求1: 直接全文搜索所有的 li 元素列表并打印
List<JXNode> jxNodes = jxDocument.selN("//li");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
//需求2: 直接全文搜索所有的 div,再逐层级搜索下面的 a 元素下的 img 元素列表并打印
jxNodes = jxDocument.selN("//div/a/img");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
//需求3: 接获取 link 元素里面 href 属性的值,注意属性要用@符号
jxNodes = jxDocument.selN("//link/@href");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
}
}
6.6 条件筛选
- 根据条件过滤选取节点
6.6.1 语法
格式 | 说明 |
---|---|
//元素[@属性=value] | 获取元素属性=value的元素 |
//元素[@属性>value]/@属性 | 获取元素属性>value的元素的所有属性的值 |
//元素[@属性=value]/text() | 获取符合条件元素的纯文本数据 |
//元素[@属性=value]/html() | 获取符合条件元素的html数据(包括标签) |
注意事项
- 如果value是一个包含“-”的字符串,那么需要用单引号括住;
6.6.2 示例代码
public class Demo04 {
public static void main(String[] args) throws XpathSyntaxErrorException, IOException {
Document document = Jsoup.parse(new File(Demo04.class.getResource("/index.html").getPath()),"utf-8" );
//使用Document对象获得对应的额JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//需求1: 搜索li,属性为class="nav-active"的元素并打印
List<JXNode> jxNodes = jxDocument.selN("//li[@class='nav-active']");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
//需求2: 属性为data-slide-to大于0的元素,再查询data-slide-to的属性值
jxNodes = jxDocument.selN("//li[@data-slide-to>0]/@data-slide-to");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
//需求3: 搜索a标签,属性为href="login.html"的元素,得到它的文本。
jxNodes = jxDocument.selN("//a[@href='login.html']/text()");
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
}
}