spring源碼附錄(1)java實現對XML格式的驗證

最近在看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.cnblogs.com/zhengcheng/p/4278899.html
看下面student.xml:

<?xml version="1.0"?>
<!DOCTYPE 學生名冊 SYSTEM "student.dtd">
<學生名冊>
    <學生 學號="t1">
        <姓名>張三</姓名>
        <性別>男</性別>
        <年齡>20</年齡>
    </學生>
    <學生 學號="t2">
        <姓名>李四</姓名>
        <性別>女</性別>
        <年齡>19</年齡>
    </學生>
</學生名冊>

我們看到上面這個XML指定的DTD驗證文件爲student.dtd:

<?xml version="1.0" encoding="UTF-8"?>

<!ELEMENT 學生名冊  (學生*)>
<!ELEMENT 學生 (姓名,性別,年齡)>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 性別 (#PCDATA)>
<!ELEMENT 年齡 (#PCDATA)>
<!ATTLIST 學生 學號 ID #REQUIRED>

那麼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<nodeList.getLength();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<childList.getLength();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文件進行驗證,

<!DOCTYPE 學生名冊 SYSTEM "student.dtd">

student.dtd即指定了驗證文件的位置。

二、spring源碼中對XML文件的驗證的處理

在spring中,爲網絡地址:

<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"  
"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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章