对于Xml来说有两种约束方式:DTD,XSD(xml schema defenition),在Spring中用来判断以何种解析方式的就是XmlValidationModeDetector类。这其中有一些方法我觉得设计的很巧妙:
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
//如果读取的行是注释或空则略过
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) { //DOCTYPE = "DOCTYPE"
isDtdValidated = true;
break;
}
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}
//START_COMMENT = "<!--"; END_COMMENT = "-->"
private String consumeCommentTokens(String line) {
//如果是普通的语句就直接返回
if (!line.contains(START_COMMENT) && !line.contains(END_COMMENT)) {
return line;
}
String currLine = line;
while ((currLine = consume(currLine)) != null) {
if (!this.inComment && !currLine.trim().startsWith(START_COMMENT)) {
return currLine;
}
}
return null;
}
private String consume(String line) {
int index = (this.inComment ? endComment(line) : startComment(line));
return (index == -1 ? null : line.substring(index));
}
private int startComment(String line) {
return commentToken(line, START_COMMENT, true);
}
private int endComment(String line) {
return commentToken(line, END_COMMENT, false);
}
private int commentToken(String line, String token, boolean inCommentIfPresent) {
int index = line.indexOf(token);
if (index > - 1) {
this.inComment = inCommentIfPresent;
}
return (index == -1 ? index : index + token.length());
}
这些代码完成了这些操作:首先如果是普通的语句就判断是否有"DOCTYPE";如果是注释语句呢?这就是我觉的设计巧妙的地方:
首先,boolean inComment标记用来标记当前状态是否在注释语句内`int index = (this.inComment ? endComment(line) : startComment(line));
刚开始碰到一个注释语句,会执行startComment(line),inComment变为true,返回一个剔除"<! --"的String,回到consumeCommentTokens方法,while循环继续。
接着会执行endComment(line),如果注释结束则inComment变为false,返回一个空String(即String内部value[]为空,但是!=null),该空会被返回给consumeCommentTokens方法,然后被忽略掉;如果注释没结束,即没检测到
“-->”,inCommen仍为true