XML格式校验,有点繁琐的字符串处理,稍微不小心就会错,逻辑要清晰,真实数据是必须的,不然WA了绝对DEBUG半死。。其实题目给的规则不算太多了,如果是真实XML的话会超级严格繁琐。。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
public class Main
{
private static final String START = "<?xml version=\"1.0\"?>";
private static final String END = "<?end?>";
static Stack<Node> stack = new Stack<Node>();
static class Node
{
String name;
Node parent;
List<Node> child = new ArrayList<Node>();
Set<String> attr = new HashSet<String>();
public Node(String name)
{
this.name = name;
}
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String line = sc.nextLine().trim();
while (!line.equals(START))
line = sc.nextLine().trim();
StringBuilder sb = new StringBuilder();
while (true)
{
line = sc.nextLine().trim();
while (!line.equals(START) && !line.equals(END))
{
sb.append(line);
line = sc.nextLine().trim();
}
System.out.println(isWellFormed(sb) ? "well-formed"
: "non well-formed");
sb = new StringBuilder();
if (line.equals(END))
break;
}
sc.close();
}
static Node createNode(String tag)
{
tag = tag.trim();
String[] ss = tag.split("\\s+");
Node node = new Node(ss[0]);
for (int i = 1; i < ss.length; i++)
{
String attr = createAttr(ss[i]);
if (attr == null || node.attr.contains(attr))
return null;
node.attr.add(attr);
}
return node;
}
static String createAttr(String s)
{
if (s.indexOf('=') == -1)
return null;
String[] ss = s.split("=");
if (ss.length != 2)
return null;
if (ss[1].startsWith("\"") && ss[1].endsWith("\""))
return ss[0];
return null;
}
static boolean checkParent(Node now, Node parent)
{
while (parent != null)
{
if (parent.name.equals(now.name))
return false;
parent = parent.parent;
}
return true;
}
static boolean isWellFormed(StringBuilder sb)
{
stack.clear();
int now = 0;
String s = sb.toString();
boolean root = false;
while (true)
{
int begin = s.indexOf('<', now);
if (begin == -1)
break;
int end = s.indexOf('>', begin);
String tag = s.substring(begin + 1, end);
if (tag.endsWith("/"))
{
Node node = createNode(tag.substring(0, tag.length() - 1));
if (node == null)
return false;
if (stack.isEmpty())
{
if (root)
return false;
else
root = true;
}
else
{
Node parent = stack.peek();
if (checkParent(node, parent))
{
parent.child.add(node);
node.parent = parent;
}
else
return false;
}
}
else if (!tag.startsWith("/"))
{
Node node = createNode(tag);
if (node == null)
return false;
if (stack.isEmpty() && root)
return false;
if (stack.isEmpty())
{
root = true;
stack.push(node);
}
else
{
Node parent = stack.peek();
if (checkParent(node, parent))
{
parent.child.add(node);
node.parent = parent;
stack.push(node);
}
else
return false;
}
}
else
{
String name = tag.substring(1).trim();
if (stack.isEmpty() || !stack.peek().name.equals(name))
return false;
stack.pop();
}
now = end + 1;
}
return stack.isEmpty();
}
}