SAX解析DocumentBuilderFactory的使用

参考 spring 解析 xml

public class TestGetXmlBean {
    public static class SimpleSaxErrorHandle implements ErrorHandler {

        @Override
        public void warning(SAXParseException exception) throws SAXException {

        }

        @Override
        public void error(SAXParseException exception) throws SAXException {
            throw exception;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
            throw exception;
        }
    }

    public static void main(String[] args) throws Exception {
        InputStream file = TestGetXmlBean.class.getClassLoader().getResourceAsStream("testBean.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 是否需要验证(比如 dtd 验证)
        factory.setValidating(true);
        // 是否使用命名空间
        factory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        // 设置了需要验证时错误信息会被捕获
        documentBuilder.setErrorHandler(new SimpleSaxErrorHandle());
        // 自定义 dtd 文件
        documentBuilder.setEntityResolver(new BeansDtdResolver());
        try {
             Document document = documentBuilder.parse(file);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

测试 bean 文件如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans default-lazy-init="1"><bean id="someMessageSource" name="yourMessageSource" class="org.springframework.context.support.StaticMessageSource"/><bean class="org.springframework.context.support.ClassPathXmlApplicationContext" lazy-init="true">
        <constructor-arg value="someNonExistentFile.xml"/>
    </bean>
</beans>

default-lazy-init 的属性这里故意写了个错的

1. 验证 validating 属性

设置需要验证

{
        InputStream file = TestGetXmlBean.class.getClassLoader().getResourceAsStream("testBean.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 是否需要验证(比如 dtd 验证)
        factory.setValidating(true);
        // 是否使用命名空间
        factory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        // 设置了需要验证时错误信息会被捕获
        documentBuilder.setErrorHandler(new SimpleSaxErrorHandle());
//        // 自定义 dtd 文件
//        documentBuilder.setEntityResolver(new BeansDtdResolver());
        try {
             Document document = documentBuilder.parse(file);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

成功抛出错误

Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\JavaProject\TestSpring\target\classes" TestGetXmlBean
org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 30; 值为 "1" 的属性 "default-lazy-init" 必须具有列表 "true false " 中的值。
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:284)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.validateDTDattribute(XMLDTDValidator.java:1392)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.addDTDDefaultAttrsAndValidate(XMLDTDValidator.java:1311)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleStartElement(XMLDTDValidator.java:1917)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.startElement(XMLDTDValidator.java:742)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3132)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:852)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:842)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
	at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
	at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
	at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
	at TestGetXmlBean.main(TestGetXmlBean.java:46)

Process finished with exit code 0

设置不需要验证

{
        InputStream file = TestGetXmlBean.class.getClassLoader().getResourceAsStream("testBean.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 是否需要验证(比如 dtd 验证)
        factory.setValidating(false);
        // 是否使用命名空间
        factory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        // 设置了需要验证时错误信息会被捕获
        documentBuilder.setErrorHandler(new SimpleSaxErrorHandle());
//        // 自定义 dtd 文件
//        documentBuilder.setEntityResolver(new BeansDtdResolver());
        try {
             Document document = documentBuilder.parse(file);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

执行成功没有报错

2.验证自定义 dtd 文件

{
        InputStream file = TestGetXmlBean.class.getClassLoader().getResourceAsStream("testBean.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 是否需要验证(比如 dtd 验证)
        factory.setValidating(true);
        // 是否使用命名空间
        factory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        // 设置了需要验证时错误信息会被捕获
        documentBuilder.setErrorHandler(new SimpleSaxErrorHandle());
//        // 自定义 dtd 文件
        documentBuilder.setEntityResolver(new BeansDtdResolver());
        try {
             Document document = documentBuilder.parse(file);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
public class BeansDtdResolver implements EntityResolver {


    @Override
    @Nullable
    public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
        InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("my-beans.dtd");
        InputSource inputSource = new InputSource(resourceAsStream);
        inputSource.setPublicId(publicId);
        inputSource.setSystemId(systemId);
        return inputSource;
    }


    @Override
    public String toString() {
        return "EntityResolver for spring-beans DTD";
    }

}    

1)publicId 和 systemId 对应 xml 头部文件的声明,比如以下 publicId 就是 -//SPRING//DTD BEAN 2.0//EN,systemId 是 https://www.springframework.org/dtd/spring-beans-2.0.dtd

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">

2)InputResource 是指验证文件(dtd) ,默认使用 systemId 所指向的验证文件,然后 resolveEnitty 返回的新的 InputSource
3)更改 dtd 文件如下

   <!ATTLIST beans default-lazy-init (true | false|1) "false">
        <!ATTLIST beans default-merge (true | false) "false">
        <!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no">
        <!ATTLIST beans default-init-method CDATA #IMPLIED>
        <!ATTLIST beans default-destroy-method CDATA #IMPLIED>

再执行代码不再报错了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值