蓝港在线:xml字符串文件的解析
题目详情:
本题来自蓝港在线技术团队的idea,详情如下:
XML-可扩展标记语言 ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言,被广泛的运用于数据传输和存储。请编写一段程序,不使用语言之外的开源库,解析对应的XML文件,并格式化后在屏幕上打印出来。
举个例子如下,当给定下述XML文件时:
<?xml version="1.0" ?>
<Books>
<Book>
<Name = “The C++ Programming Language” Author=”Bjarne Stroustrup” />
</Book>
<Book>
<Name = “Effective C++” Author = “Scott Meyers” />
</Book>
</Books>
它对应的输出应该是:
Books
Book 1
Name:The C++ Programming Language
Author:Bjarne Stroustrup
Book 2
Name:Effective C++
Author:Scott Meyers
输入:简化的一段xml文件,用字符串表示,如下(属性名字不包含引号和等号,也不包含大于小于等特殊字符,详细规则见下面的答题说明)
string in = "<?xml version=\"1.0\" ?><Books><Book><Name = \"The C++ Programming Language\" Author=\"Bjarne Stroustrup\" /></Book><Book><Name = \"Effective C++\" Author = \"Scott Meyers\" /></Book></Books>";
输出:对输入的xml字符串解析,得到输出如下:
string out = "Books\r\n\tBook 1\r\n\t\tName:The C++ Programming Language\r\n\t\tAuthor:Bjarne Stroustrup\r\n\tBook 2\r\n\t\tName:Effective C++\r\n\t\tAuthor:Scott Meyers";
函数原型:
C++ ParsingXML(string in);
Java ParsingXML(String in);
C# ParsingXML(string input)
答题说明:
1、xml分为三级,一级为大类,二级为实体,三级为属性
2、三级之间用换行间隔,每级间开始用缩格。
3、二级对象后间隔一个空格,并输出对象所在xml中的顺序号
4、第三级顺序输出属性名称和属性值,属性名和属性值间用:间隔
5、输入格式:
输入为单一xml格式字符串,其中带有"字符。可能带有回车换行符。
6、输出格式:
输出数据中不带"字符,输出格式中的每行开头使用Tab字符作为缩进。
7、属性名字不包含引号和等号,不包含大于小于等特殊字符。
8、不能使用语言之外的开源库。
这题就是写一个简单xml解析,归根结底是手写一个简单词法分析器。不多说,上通过代码。这种东西不应该出现在庞果英雄会上。。。。
public class XMLParse
{
public static String ParsingXML(String in)
{
char[] c = in.toCharArray();
Lexer t = new Lexer(c);
StringBuffer r = new StringBuffer();
Token to = t.next();
if(to.type == TokenType.EOF){
return null;
}
r.append(to.name);
int j = 1;
while (t.has_next()) {
Token s = t.next();
if(s.type == TokenType.ARRT){
r.append("\r\n\t"+s.name+" "+(j++));
}else if(s.type == TokenType.VALUE){
r.append("\r\n\t\t"+s.name);
}
}
return r.toString();
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
public static void main(String args[])
{
String in = "<?xml version=\"1.0\" ?>\r\n<Books></Books>";
String out = ParsingXML(in);
System.out.println(out);
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
}
class Token {
public Token(TokenType type, String name) {
this.type = type;
this.name = name;
}
public TokenType type;
public String name;
public String toString(){
return type+":"+name;
}
}
enum TokenType {
ROOT, ARRT, VALUE,UNEXCEPT,EOF;
}
class Lexer {
private char[] c;
int index = 0;
char p;
public Lexer(char[] c) {
this.c = c;
}
public char readc() {
if(index >= c.length){
return 0;
}
return c[index++];
}
public boolean has_next() {
return index < c.length;
}
public Token next() {
p = readc();
if(p == 0){
return new Token(TokenType.EOF, "EOF");
}
while (true) {
if (p == ' ' || p == '\r' || p == '\n' || p == '\t') {
p = readc();
}
else {
break;
}
}
if (p == '<') {
return next();
}
else if (p == '?') {
while (p != '>') {
//NOP
p = readc();
}
return next();
}
else if (Character.isLetter(p)) {
StringBuffer s = new StringBuffer();
while (Character.isLetter(p)) {
s.append(p);
p = readc();
}
while (true) {
if (p == ' ' || p == '\r' || p == '\n' || p == '\t') {
p = readc();
}
else {
break;
}
}
if(p == '>'){
return new Token(TokenType.ARRT,s.toString());
}else if(p == '='){
p = readc();
s.append(":");
}
while (true) {
if (p == ' ' || p == '\r' || p == '\n' || p == '\t') {
p = readc();
}
else {
break;
}
}
if (p == '"') {
p = readc();
while (p != '"') {
s.append(p);
p = readc();
}
return new Token(TokenType.VALUE,s.toString());
}
}
else if (p == '/') {
StringBuffer s = new StringBuffer();
p = readc();
if (Character.isLetter(p)) {
while (p != '>') {
s.append(p);
p = readc();
}
if(has_next()){
return next();
}else{
return new Token(TokenType.EOF, "EOF");
}
}
else {
return next();
}
}
return new Token(TokenType.UNEXCEPT, "EOF");
}
}