最近在看spring源碼,涉及到xml文檔的解析、xml文檔的格式驗證,發現自己對xml解析的基礎較為薄弱,本篇博客復習下DOM方式解析xml(即spring解析xml的方式)。
DOM解析XML是將整個XML作為一個對象,占用內存較多。另外一個java官方的XML解析方式SAX是邊掃描邊解析,自頂向下依次解析,占用內存較少。
一、java實現對XML格式的驗證
可以使用兩種驗證模式(DTD、XSD)保證XML文件格式正確,DTD和XSD均是XML約束描述語言,是XML文件的驗證機制。本文以DTD為例。
DTD文件格式請參考:http://www..com/zhengcheng/p/4278899.html
看下面student.xml:
張三姓名>
男性別>
20年齡>
學生>
李四姓名>
女性別>
19年齡>
學生>
學生名冊>
我們看到上面這個XML指定的DTD驗證文件為student.dtd:
那么java DOM解析XML如何實現驗證?
下面使用DOM解析student.xml:
public class test {
public static void main(String[] args) {
DocumentBuilderFactory buildFactory = DocumentBuilderFactory.newInstance();
//開啟XML格式驗證
buildFactory.setValidating(true);
try {
DocumentBuilder build = buildFactory.newDocumentBuilder();
//指定驗證出錯處理類MyErrorHandle
build.setErrorHandler(new MyErrorHandler());
//自定義解析方式,如果不設置,則使用默認實現
build.setEntityResolver(new MyResolveEntity());
Document doc = build.parse("student.xml");
getStudents(doc);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void getStudents(Document doc) {
Element root = doc.getDocumentElement();
NodeList nodeList = root.getElementsByTagName("學生");
for(int i=0;i
Node node = nodeList.item(i);
NamedNodeMap map = node.getAttributes();
System.out.println(map.item(0).getTextContent());
//子節點
NodeList childList = node.getChildNodes();
for(int j=0;j
Node childNode = childList.item(j);
System.out.println(childNode.getTextContent());
}
}
}
}
public class MyErrorHandler implements ErrorHandler{
@Override
public void warning(SAXParseException exception) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void error(SAXParseException exception) throws SAXException {
System.out.println("發生了錯誤!"+exception.getMessage());
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
// TODO Auto-generated method stub
}
}
public class MyResolveEntity implements EntityResolver{
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return new InputSource("student.dtd");
//return null;
}
}
如果不設置setEntityResolver,則會使用XML中指定位置的DTD文件進行驗證,
student.dtd即指定了驗證文件的位置。
二、spring源碼中對XML文件的驗證的處理
在spring中,為網絡地址:
/p>
"http://www.springframework.org/dtd/spring-beans.dtd">
publicId:-//SPRING//DTD BEAN//EN
systemId:http://www.springframework.org/dtd/spring-beans.dtd
如果設置了setEntityResolver,則會按照EntityResolver進行XML驗證:先去項目中尋找spring-beans.xsd,如果未獲取到則按照網絡地址尋找。
以spring中 Spring-beans.dtd為例:
public class BeansDtdResolver implements EntityResolver {
private static final String DTD_EXTENSION = ".dtd";
private static final String DTD_NAME = "spring-beans";
private static final Log logger = LogFactory.getLog(BeansDtdResolver.class);
@Override
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Trying to resolve XML entity with public ID [" + publicId +
"] and system ID [" + systemId + "]");
}
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf("/");
int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
if (dtdNameStart != -1) {
String dtdFile = DTD_NAME + DTD_EXTENSION;
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
}
}
}
}
// Use the default behavior -> download from website or wherever.
return null;
}
}