同时指定DTD与XSD时,XML验证器是否会忽略DTD?
解决XML同时指定DTD和XSD时仅XSD生效的问题
你观察到的这个现象完全是正常的——主流XML验证器(包括你用的XMLSpy 2018sp1和Xerces)在同时遇到DTD和XSD声明时,都会优先采用XSD进行验证,自动忽略DTD。这是因为XSD的功能比DTD强大太多,不仅支持数据类型约束、命名空间,还能更精细地定义结构,W3C的规范也更推荐XSD作为现代XML的主要验证机制。
但你的需求很明确:要基于不可修改的行业DTD做基础验证,再用自定义XSD做额外约束,必须同时通过两者的检查。直接同时指定两者肯定行不通,这里给你几个可行的解决方案:
方案1:分两次独立验证(最直接的方式)
把验证流程拆成两步,分别完成DTD和XSD的验证:
- 第一步:纯DTD验证
在工具中单独启用DTD验证模式。比如在XMLSpy里,你可以在验证设置里取消XSD相关的勾选,只保留“DTD验证”选项;用Xerces的StdInParse时,通过参数指定仅加载DTD进行验证(命令类似java org.apache.xerces.parsers.StdInParse -dtd your.xml,具体参数可以参考Xerces文档)。这一步确保XML符合行业标准DTD的要求。 - 第二步:纯XSD验证
切换到XSD验证模式,用你的自定义XSD做二次检查。这一步可以确保XML满足你额外添加的约束规则。
只有当两次验证都通过时,才认为XML是合法的。
方案2:将DTD规则转换为XSD并合并约束(更高效的方式)
虽然你说DTD是不可修改的行业标准,但可以把DTD的所有规则完整转换为XSD,再把你的自定义约束合并到这个转换后的XSD中,这样只需要一次XSD验证就能同时覆盖原DTD和自定义规则:
- 很多工具支持DTD到XSD的转换,比如XMLSpy就有内置的转换功能,你可以直接导入DTD生成对应的XSD。
- 转换完成后,一定要仔细核对生成的XSD,确保没有丢失DTD中的关键规则(比如某些实体定义、元素嵌套要求),再添加你的自定义约束。
方案3:自定义代码实现双重验证(灵活度最高)
如果工具层面的解决方案不够满足需求,你可以用代码实现双重验证逻辑。比如用Java结合Xerces编写验证流程:
// 自定义错误处理器,用于捕获验证错误 class ValidationErrorHandler implements ErrorHandler { @Override public void warning(SAXParseException e) throws SAXException { System.err.println("警告: " + e.getMessage()); } @Override public void error(SAXParseException e) throws SAXException { System.err.println("错误: " + e.getMessage()); throw e; // 抛出错误终止验证 } @Override public void fatalError(SAXParseException e) throws SAXException { System.err.println("致命错误: " + e.getMessage()); throw e; } } // 第一步:DTD验证 DocumentBuilderFactory dtdFactory = DocumentBuilderFactory.newInstance(); dtdFactory.setValidating(true); dtdFactory.setNamespaceAware(false); DocumentBuilder dtdBuilder = dtdFactory.newDocumentBuilder(); dtdBuilder.setErrorHandler(new ValidationErrorHandler()); dtdBuilder.parse(new FileInputStream("your.xml")); // 第二步:XSD验证 DocumentBuilderFactory xsdFactory = DocumentBuilderFactory.newInstance(); xsdFactory.setValidating(false); xsdFactory.setNamespaceAware(true); xsdFactory.setAttribute( "http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema" ); xsdFactory.setAttribute( "http://java.sun.com/xml/jaxp/properties/schemaSource", new File("your-custom.xsd") ); DocumentBuilder xsdBuilder = xsdFactory.newDocumentBuilder(); xsdBuilder.setErrorHandler(new ValidationErrorHandler()); xsdBuilder.parse(new FileInputStream("your.xml"));
这段代码会先执行DTD验证,只有通过后才会进行XSD验证,任何一步出错都会抛出异常。
总结一下,直接让验证器同时使用DTD和XSD是不符合主流实现逻辑的,分步骤验证或者合并约束是更可行的路径。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

