像xml,html这些标记行语言,我们通常会去采用java自带的解析工具去解析,如果我们要自己写一个类似于pull解析器或者dom解析器,能实现吗?这当然是很麻烦的,但是我们这里可以写一个稍微简单些的解析器。
比如我们要解析的文本是:
<xxml>
<span>
<button id="btn1" width="40" height="40"/>
<label id="label1" width="30" height="40"/>
</xxml>
这只是一段简单的例子,我们现在的需求是要解析出span,button,label这三个标签,收集每个标签里面的属性,并在控制台打印出来。
我们这里不会用到java自带的xml解析器。而是重新去写一个简单的解析器 。
这里的思路是这样的:
在循环里不停去读字符流的字符,直到遇到结尾为止。
解析到”<”表明是标签控件开始。
如果解析到“/”表示是标签结尾。
打印处理标签内属性
如果是标签内的属性的话,就要把属性加入到当前标签里面。
关键代码如下:
public class Parser {
int pos = 0;
public static final char EOF = (char) -1;
private Reader reader ;
public Parser(String parser) {
this.reader = new StringReader(parser);
}
public void parse() throws Exception {
while (true) {
char ch = this.getChar();
if (ch == EOF)
break;
else if (ch == '<') {
} else if (ch == '/') {
this.ungetChar(2);
this.parseEndTag(pos);
System.out.println(ch + " ---- ");
break;
} else {
this.ungetChar(1);
this.parseText(pos);
}
}
return;
}
这里我们可以看到,用StingReader这个类不断去读取字符流中的数据,一直到读取完了。当解析到‘/’符号的时候表明这是一个标签的结尾,这时候我们就要执行parseEndTag结束一个完整的标签。
public void parseEndTag(int start) throws Exception {
StringBuffer temp = new StringBuffer();
while (true) {
char ch = this.getChar();
if ('<' == ch) {
ch = this.getChar();
if ('/' != ch) {
// throw new ParserException("illegal tag:" + pos);
}
} else if (' ' == ch||'/' == ch) {
}else if ('>' == ch) {
break;
} else {
temp.append(ch);
}
}
}
当我们
解析到的不是结束标签的时候,就要把
当前标签的内容收集并且打印出来。
public void parseText(int start) throws Exception {
while (true) {
char ch = this.getChar();
if (EOF == ch) {
this.ungetChar();
char data[] = this.makeString(start, pos);
break;
} else if ('<' == ch) {
//解析到 空 等各类标签后 循环解析到 < 为止, 计算进入时的字符间的内容
this.ungetChar();
char data[] = this.makeString(start, pos);
// if (data != null) {
// System.out.println(new String(data));
// //
// }
break;
}
}
}
public char[] makeString(int start, int end) throws Exception {
int length = end - start;
char data[] = new char[length];
this.reader.reset();
this.reader.skip(start);
this.reader.read(data);
String text = new String(data);
if (text.trim().equals("") ) {
data = null;
}
System.out.println("[" + start + "," + end + "]Element: " + new String(data));
printNode(text);//对于标签里面的属性,再进行解析并且打印
return data;
}
/*
* 打印一个标签里面的属性
* 具体场景可以根据
*/
private void printNode(String text) throws IOException {
Reader reader =new StringReader(text);
char c = (char) reader.read();
String temp="";
boolean first = true;
while (c != EOF) {
if (c == ' ') {
if(first)
System.out.println(temp);
else
System.out.println("Attribute:"+temp);
first = false;
temp = "";
}
temp += c;
c = (char) reader.read();
}
}
好了,接下来我们来运行程序,打印果如下:
我们看到,Element表示标签名,xml,span,button这些标签名都打印出来了。
然后有属性的标签,比如像button,里面的属性都收集过来打印出来了。
提供下完整代码地址:
https://github.com/preqel/Parser
我们已经完成了对xml的简单解析,但是还有些问题没解决:
1.嵌套标签的解析,父子元素关系。
2.对于注解符号的解析
这些内容放到后面有时间进行研究。