不一样的味道--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支持单标签。

上一篇:Establishing SSL connection without server's identity verification is not recommended. According to


下一篇:转载的spring cloud的全家桶,有空学习下