参考 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>
再执行代码不再报错了