Java XML XSD全量校验中断及XSD相对路径引用问题求助
解决方案:XML全量校验与XSD相对路径引用问题
一、实现XML全量校验(收集所有错误)
你之前自定义XsdErrorHandler未生效,大概率是两个核心问题:要么没正确将处理器绑定到Validator,要么处理器方法中抛出了异常导致校验中断。按以下步骤修正:
编写错误收集处理器
处理器需全程收集错误、警告,绝对不能在方法内抛出异常(一旦抛异常,校验会直接终止在当前错误):import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import java.util.ArrayList; import java.util.List; public class CollectingErrorHandler implements ErrorHandler { private final List<SAXParseException> errors = new ArrayList<>(); private final List<SAXParseException> warnings = new ArrayList<>(); private final List<SAXParseException> fatalErrors = new ArrayList<>(); @Override public void warning(SAXParseException exception) { warnings.add(exception); } @Override public void error(SAXParseException exception) { errors.add(exception); } @Override public void fatalError(SAXParseException exception) { fatalErrors.add(exception); } // 提供获取全量错误的方法 public List<SAXParseException> getAllErrors() { List<SAXParseException> all = new ArrayList<>(); all.addAll(warnings); all.addAll(errors); all.addAll(fatalErrors); return all; } }绑定处理器并执行校验
初始化Validator时必须显式绑定自定义处理器,确保校验全程不中断:import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import java.io.File; public class XmlValidator { public static void main(String[] args) throws Exception { // 加载主XSD文件 SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = factory.newSchema(new File("xsd/main.xsd")); Validator validator = schema.newValidator(); CollectingErrorHandler errorHandler = new CollectingErrorHandler(); *关键:*validator.setErrorHandler(errorHandler); // 绑定自定义错误处理器 // 执行校验(即使遇错也会继续) validator.validate(new StreamSource(new File("test.xml"))); // 输出所有收集到的错误信息 for (SAXParseException e : errorHandler.getAllErrors()) { System.out.printf("行号:%d,列号:%d,错误信息:%s%n", e.getLineNumber(), e.getColumnNumber(), e.getMessage()); } } }若使用JAXB的
Unmarshaller,需设置ValidationEventHandler,逻辑一致——收集错误不抛出异常,才能获取全量结果。
二、解决XSD相对路径引用失效问题
XSD存放在xsd文件夹下,相对路径引用失效是因为SchemaFactory默认解析器无法识别相对路径的资源位置,需自定义LSResourceResolver处理:
自定义相对路径资源解析器
解析器会从主XSD所在目录加载引用的XSD文件:import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class RelativePathResourceResolver implements LSResourceResolver { private final File baseDir; // 传入主XSD所在的目录 public RelativePathResourceResolver(File baseDir) { this.baseDir = baseDir; } @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { // systemId即为XSD中引用的相对路径,如./global.xsd File referencedFile = new File(baseDir, systemId); if (!referencedFile.exists()) { return null; // 找不到则交给默认解析器处理 } try { InputStream inputStream = new FileInputStream(referencedFile); LSInput lsInput = new org.apache.xerces.dom.DOMInputImpl(); lsInput.setByteStream(inputStream); lsInput.setSystemId(referencedFile.toURI().toString()); return lsInput; } catch (Exception e) { return null; } } }绑定解析器到SchemaFactory
加载Schema前设置自定义解析器,确保相对路径引用生效:// 主XSD文件对象 File mainXsd = new File("xsd/main.xsd"); // 获取主XSD所在的目录 File xsdDir = mainXsd.getParentFile(); SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); factory.setResourceResolver(new RelativePathResourceResolver(xsdDir)); // 设置自定义解析器 Schema schema = factory.newSchema(mainXsd);Maven环境下的Classpath加载适配
若XSD存放在src/main/resources/xsd下(Maven标准资源目录),可改用Classpath加载的解析器:import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import java.io.InputStream; public class ClasspathXsdResolver implements LSResourceResolver { private final String basePath; // 固定前缀,如"xsd/" public ClasspathXsdResolver(String basePath) { this.basePath = basePath; } @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { String resourcePath = basePath + systemId; InputStream inputStream = getClass().getClassLoader().getResourceAsStream(resourcePath); if (inputStream == null) { return null; } LSInput lsInput = new org.apache.xerces.dom.DOMInputImpl(); lsInput.setByteStream(inputStream); lsInput.setSystemId(resourcePath); return lsInput; } }使用方式:
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); factory.setResourceResolver(new ClasspathXsdResolver("xsd/")); Schema schema = factory.newSchema(getClass().getClassLoader().getResource("xsd/main.xsd"));
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

