不一样的味道--Html及Xml解析、格式化、遍历

简介:

TinyXmlParser一切以简单、实用、快速为主。

示例1:Xml字符串解析

比如,我们要解析一段Xml字符串,简单如下即可:

?
1
XmlDocument xmlDocument = new XmlStringParser().parse( "<title><a>a</a></title>" );

示例2:输出格式化后的Xml:

?
1
2
XmlFormater formater = new XmlFormater();
System.out.println(formater.format(xmlDocument));

运行结果如下:

?
1
2
3
< title >
   < a >a</ a >
</ title >

当然换一种写法也是可以的,比如下面:

?
1
2
3
XmlDocument xmlDocument = new XmlStringParser().parse("< title >< a >a</ a ></ title >");
XmlFormater formater = new XmlFormater();
System.out.println(formater.format(xmlDocument));
输出结果和上面是一样的。

示例3:中文标签支持

?
1
2
3
4
XmlDocument document = new XmlStringParser().parse( "<html 中='文'><head><title>aaa</title><中>中信</中></head></html>" );
document.write(System.out);
XmlFormater formater = new XmlFormater();
formater.format(document, System.out);

上面的例子用了两种方式,一种是非格式化方式输出,默认是用一行输出的;另一种是格式化输出的:

?
1
2
3
4
5
6
7
<html 中= "文" ><head><title>aaa</title><中>中信</中></head></html>
<html 中= "文" >
   <head>
     <title>aaa</title>
     <中>中信</中>
   </head>
</html>

可以看到对于中文标签及属性也有完美支持。

示例4:容错性示例

?
1
2
3
XmlDocument document = new XmlStringParser().parse( "<title><a>a</title>" );
XmlFormater formater = new XmlFormater();
formater.format(document, System.out);

上面的例子中,<a> 标签没有</a>结束标签。

输出结果如下:

?
1
2
3
< title >
   < a >a</ a >
</ title >

可以看到,它已经尽最大可能来猜测是否正确

示例5:性能测试

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
XmlNode node = null ;
 
     public NameFilterTest() {
         node = new XmlNode( "root" );
         for ( int i = 0 ; i < 60 ; i++) {
             XmlNode a = node.addNode( new XmlNode( "a" + i));
             for ( int j = 0 ; j < 60 ; j++) {
                 XmlNode b = a.addNode( new XmlNode( "b" + j));
                 for ( int k = 0 ; k < 60 ; k++) {
                     b.addNode( new XmlNode( "c" + k));
                 }
             }
         }
     }

构建这么大一棵Dom树

?
1
2
3
4
5
6
7
8
9
10
11
long t21 = System.currentTimeMillis();
FastNameFilter<XmlNode> fast = new FastNameFilter(node);
long t22 = System.currentTimeMillis();
System.out.println( "初始化用时:" + (t22 - t21));
long t1 = System.currentTimeMillis();
for ( int x = 0 ; x < 10000 ; x++) {
    XmlNode node = fast.findNode( "b6" );
}
// System.out.println(nodeName);
long t2 = System.currentTimeMillis();
System.out.println( "遍历用时:" + (t2 - t1));

运行结果如下:

?
1
2
初始化用时:48
遍历用时:20

请注意,上面的时间单位不是分钟,不是秒钟,而是毫秒。

示例6:节点过滤

对节点过滤是否方便才是最紧要的。这个功能,太过强大,因此,用例子已经演示不出它的强大了。直接贴接口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
public interface NodeFilter<T extends Node<T>> {
     /**
      * 初始化节点
      *
      * @param node
      */
     void init(T node);
 
     /**
      * 设置必须包含的属性及对应属性的值,必须存在
      *
      * @param includeAttributes
      */
     void setIncludeAttribute(Map<String, String> includeAttributes);
 
     /**
      * 设置必须包含的属性及对应的属性的值,必须存在
      *
      * @param key
      * @param value
      */
     void setIncludeAttribute(String key, String value);
 
     /**
      * 设置必须包含的属性
      *
      * @param includeAttribute
      */
     void setIncludeAttributes(String... includeAttribute);
 
     /**
      * 设置必须排除的属性及对应属性值 如果包含属性,但属性的值与Map中不相同,允许存在该属性 若包含属性且属性的值与Map中相同,则不允许存在该属性
      *
      * @param excludeAttribute
      */
     void setExcludeAttribute(Map<String, String> excludeAttribute);
 
     /**
      * 设置必须排除的属性,指定的属性不能存在
      *
      * @param excludeAttribute
      */
     void setExcludeAttribute(String... excludeAttribute);
 
     /**
      * 设置必须包含的内容,只需要context中包include该值就行
      *
      * @param includeText
      */
     void setIncludeText(String... includeText);
 
     /**
      * 设置必须排除的内容
      *
      * @param excludeText
      */
     void setExcludeText(String... excludeText);
 
     /**
      * 设置必须包含的子节点
      *
      * @param includeNode
      */
     void setIncludeNode(String... includeNode);
 
     /**
      * 设置父节点不允许的节点名称
      *
      * @param excludeByNode
      */
 
     void setExcludeByNode(String... excludeByNode);
 
     /**
      * 设置父节点必须包含的节点名称
      *
      * @param includeByNode
      */
     void setIncludeByNode(String... includeByNode);
 
     /**
      * 设置必须排除的子节点
      *
      * @param excludeNode
      */
 
     void setExcludeNode(String... excludeNode);
 
     /**
      * 设置至少包含一个指定名称的节点
      *
      * @param xorSubNode
      */
     void setXorSubNode(String... xorSubNode);
 
     /**
      * 设置至少包含一个指定名称属性
      *
      * @param xorProperties
      */
     void setXorProperties(String... xorProperties);
 
     /**
      * 清除过滤条件
      */
     void clearCondition();
 
     /**
      * 设置要搜索的节点名称
      */
     void setNodeName(String nodeName);
 
     /**
      * 查找指定节点名称及满足其他条件的节点列表
      *
      * @param nodeName
      * @return
      */
     List<T> findNodeList(String nodeName);
 
     /**
      * 根据名字及其他条件查找节点,如果有多个,也只返回第一个
      *
      * @param nodeName
      *            要查找的节点名称
      * @return
      */
     T findNode(String nodeName);
 
     /**
      * 搜索符合设置的节点名称的节点,如果有多个,则只返回找到的第一个
      *
      * @return
      */
     T findNode();
 
     /**
      * 搜索符合设置的节点名称的节点列表
      *
      * @return
      */
     List<T> findNodeList();
}

也就是说它支持节点指定属性名及指定属性值过滤(可以指定多组)、指定属性名过滤(不管是什么值都可以,可以指定多个)、可以指定排除属性及属性值(即不能包含的属性名及值,可以包含多组)、不能包含的属性(可以包含多组)、包含文本内容(可以指定多组)、不能包含的文件内容(可以指定多组),可以指定包含的节点名(可以指定多组)、可以指定不能包含的节点(可以指定多组)、可以指定必须在某个节点下(可以指定多组)、可以指定不能在某个节点下(可以指定多组)、可以指定至少包含某几个节点中的一个,可以指定至下包含某几个属性中的一个,可以根据节点名进行搜索。

上面的所有条件可以组合起来一起搜索。

说了这么多,看看测试用例:

?
1
2
3
4
5
6
7
8
9
10
node = new XmlNode( "root" );
XmlNode n1 = node.addNode( new XmlNode( "aa" ));
n1.setAttribute( "a" , "av" );
n1.setAttribute( "b" , "bv" );
n1.addNode( new XmlNode( "a" ));
n1 = node.addNode( new XmlNode( "aa" ));
n1.setAttribute( "a" , "av1" );
n1.setAttribute( "b" , "bv1" );
n1.setAttribute( "c" , "cv1" );
n1.addNode( new XmlNode( "b" ));

上面构建了一棵Dom树:

?
1
2
3
4
5
6
7
8
9
10
<root>
   <aa a= "av" b= "bv" >
     <a>
     </a>
   </aa>
   <aa a= "av1" b= "bv1" c= "cv1" >
     <b>
     </b>
   </aa>
</root>

下面是一堆的测试用例了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
filter = new NameFilter(node);
filter.clearCondition();
assertEquals( 1 , filter.findNodeList( "root" ).size());
filter.setExcludeAttribute( "c" );
assertEquals( 1 , filter.findNodeList( "aa" ).size());
// 测试包含属性名
filter.clearCondition();
assertEquals( 1 , filter.findNodeList( "root" ).size());
filter.setIncludeAttributes( "c" );
assertEquals( 1 , filter.findNodeList( "aa" ).size());
// 测试包含指定属性值
filter.clearCondition();
Hashtable<String, String> pht = new Hashtable<String, String>();
pht.put( "a" , "av1" );
filter.setIncludeAttribute(pht);
assertEquals( 1 , filter.findNodeList( "aa" ).size());
filter.setExcludeAttribute( "c" );
assertEquals( 0 , filter.findNodeList( "aa" ).size());
// 测试包含指定节点
filter.clearCondition();
filter.setIncludeNode( "a" );
assertEquals( 1 , filter.findNodeList( "aa" ).size());
filter.setIncludeAttributes( "c" );
assertEquals( 0 , filter.findNodeList( "aa" ).size());
// 测试包含指定节点
filter.clearCondition();
filter.setExcludeNode( "c" );
assertEquals( 2 , filter.findNodeList( "aa" ).size());

测试用例写得比较丑,但是对它的使用还是做了一个简单的演示。

上面所有的例子当中,把X变成Ht,就是针对Html解析器的了,API完全一致,用法完全相同。

区别在于Xml的标签及属性名是大小写敏感的,而Html是大小写不敏感的。

另外Html支持单标签。

相关文章
|
2月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
183 1
|
2月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
88 15
|
3月前
|
数据采集 存储 调度
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
在Python网页抓取领域,BeautifulSoup和Scrapy是两款备受推崇的工具。BeautifulSoup易于上手、灵活性高,适合初学者和简单任务;Scrapy则是一个高效的爬虫框架,内置请求调度、数据存储等功能,适合大规模数据抓取和复杂逻辑处理。两者结合使用可以发挥各自优势,例如用Scrapy进行请求调度,用BeautifulSoup解析HTML。示例代码展示了如何在Scrapy中设置代理IP、User-Agent和Cookies,并使用BeautifulSoup解析响应内容。选择工具应根据项目需求,简单任务选BeautifulSoup,复杂任务选Scrapy。
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
|
3月前
|
数据采集 前端开发 API
SurfGen爬虫:解析HTML与提取关键数据
SurfGen爬虫:解析HTML与提取关键数据
|
6月前
|
XML 数据采集 数据格式
Python 爬虫必备杀器,xpath 解析 HTML
【11月更文挑战第17天】XPath 是一种用于在 XML 和 HTML 文档中定位节点的语言,通过路径表达式选取节点或节点集。它不仅适用于 XML,也广泛应用于 HTML 解析。基本语法包括标签名、属性、层级关系等的选择,如 `//p` 选择所有段落标签,`//a[@href=&#39;example.com&#39;]` 选择特定链接。在 Python 中,常用 lxml 库结合 XPath 进行网页数据抓取,支持高效解析与复杂信息提取。高级技巧涵盖轴的使用和函数应用,如 `contains()` 用于模糊匹配。
127 7
|
6月前
|
XML JavaScript 前端开发
如何解析一个 HTML 文本
【10月更文挑战第23天】在实际应用中,根据具体的需求和场景,我们可以灵活选择解析方法,并结合其他相关技术来实现高效、准确的 HTML 解析。随着网页技术的不断发展,解析 HTML 文本的方法也在不断更新和完善,
|
6月前
|
JavaScript API 开发工具
<大厂实战场景> ~ Flutter&鸿蒙next 解析后端返回的 HTML 数据详解
本文介绍了如何在 Flutter 中解析后端返回的 HTML 数据。首先解释了 HTML 解析的概念,然后详细介绍了使用 `http` 和 `html` 库的步骤,包括添加依赖、获取 HTML 数据、解析 HTML 内容和在 Flutter UI 中显示解析结果。通过具体的代码示例,展示了如何从 URL 获取 HTML 并提取特定信息,如链接列表。希望本文能帮助你在 Flutter 应用中更好地处理 HTML 数据。
217 1
|
7月前
|
XML 数据格式
HTML 实例解析
本文介绍了HTML中常见元素的使用方法,包括`&lt;p&gt;`、`&lt;body&gt;`和`&lt;html&gt;`等。详细解析了这些元素的结构和作用,并强调了正确使用结束标签的重要性。此外,还提到了空元素的使用及大小写标签的规范。
|
2月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
211 29
|
2月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
73 3

推荐镜像

更多