如何用Apache Commons Configuration2实现自定义XSD验证XML配置
问题
我希望通过Apache Commons Configuration2加载XML配置,同时执行XSD验证。要求用于验证的XSD由应用提供,而非不可信配置文件中链接的XSD。
我在官方文档和StackOverflow中均未找到匹配示例。有一个类似问题的回答仅适用于Apache Commons Configuration1,无法满足我的需求。
补充说明:
Apache Commons Configuration文档中的XSD验证示例如下:
Parameters params = new Parameters(); FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class) .configure(params.xml() .setFileName("myconfig.xml") .setSchemaValidation(true)); // This will throw a ConfigurationException if the XML document does not // conform to its Schema. XMLConfiguration config = builder.getConfiguration();
该示例是读取XML配置文件并根据其内部引用的XSD进行验证,但我需要在代码中指定应用提供的XSD来验证。以下是我的尝试:
File f = new File(xmlfile); log.info("Reading {}", f.getAbsoluteFile()); URL url = getClass().getResource("/schema/configuration.xsd"); log.trace("loading XSD from {}", url); SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Source schemaFile = new StreamSource(url.openStream()); Schema schema = factory.newSchema(schemaFile); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setSchema(schema); dbf.setNamespaceAware(true); dbf.setValidating(false); // ignore XSD references within the document DocumentBuilder db = dbf.newDocumentBuilder(); MyErrorHandler meh = new MyErrorHandler(); db.setErrorHandler(meh); db.parse(f); // <<<=============== note this line Parameters params = new Parameters(); params.xml() .setSchemaValidation(true) .setDocumentBuilder(db); FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class) .configure(params.xml().setFile(f)); config = builder.getConfiguration();
注意db.parse(f);这一行:
- 保留该行时,文档会被验证,
MyErrorHandler会收到警告、错误和致命错误。 - 移除该行时,无论文档是否有效都会被加载。
这意味着尽管我已正确配置了DocumentBuilder,但将其传入配置构建器params.setDocumentBuilder()并未生效。
解决方案
问题出在重复调用params.xml():第一次调用时你配置了setDocumentBuilder(db),但第二次调用params.xml().setFile(f)时,会生成一个全新的XMLBuilderParameters实例,之前的配置完全丢失。
正确的做法是创建单个XMLBuilderParameters实例,链式配置所有属性后再传入构建器:
File f = new File(xmlfile); log.info("Reading {}", f.getAbsoluteFile()); URL url = getClass().getResource("/schema/configuration.xsd"); log.trace("loading XSD from {}", url); SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Source schemaFile = new StreamSource(url.openStream()); Schema schema = factory.newSchema(schemaFile); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setSchema(schema); dbf.setNamespaceAware(true); dbf.setValidating(false); // 忽略配置文件内部的XSD引用 DocumentBuilder db = dbf.newDocumentBuilder(); MyErrorHandler meh = new MyErrorHandler(); db.setErrorHandler(meh); // 关键:创建一个XMLBuilderParameters实例并链式配置所有参数 XMLBuilderParameters xmlParams = params.xml() .setFile(f) .setDocumentBuilder(db); // 传入绑定了XSD的自定义DocumentBuilder FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class) .configure(xmlParams); // 加载配置时会自动用指定XSD验证,无需手动调用db.parse(f) config = builder.getConfiguration();
核心要点
- 避免重复调用
params.xml(),每次调用都会生成新的参数对象,导致之前的配置失效。 - 自定义的
DocumentBuilder已绑定你的XSD和错误处理器,构建器加载配置时会使用该实例解析XML,自动触发验证流程。 - 移除手动的
db.parse(f)调用,让配置构建器完成整个解析+验证+加载流程,避免重复解析。
修改后,当XML不符合指定XSD时,会通过MyErrorHandler抛出错误,阻止无效配置被加载。
内容的提问来源于stack exchange,提问作者queeg
相关产品推荐
相关产品推荐

