• 通过xsd校验xml


    不依赖第三方工具

    核心代码

    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    import javax.xml.XMLConstants;
    import javax.xml.transform.Source;
    import javax.xml.transform.stream.StreamSource;
    import javax.xml.validation.Schema;
    import javax.xml.validation.SchemaFactory;
    import javax.xml.validation.Validator;
    
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.SAXException;
    
    public class XmlValidateUtils {
    	
    	private static Validator initValidator(InputStream xsdInputStream) throws SAXException {
    		SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    		Source schemaFile = new StreamSource(xsdInputStream);
    		Schema schema = factory.newSchema(schemaFile);
    		return schema.newValidator();
    	}
    	
    	private static boolean isValid(Validator validator, InputStream xmlInputStream) throws IOException {
    	    try {
    	        validator.validate(new StreamSource(xmlInputStream));
    	        return true;
    	    } catch (SAXException e) {
    	        return false;
    	    }
    	}
    	
    	private static boolean isValid(Validator validator, String xml) throws IOException {
    		try (
    				ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xml.getBytes());
    				) {
    			return isValid(validator, xmlInputStream);
    		}
    	}
    	
    	/**
    	 * 验证xml文档是否符合xsd校验
    	 * @param xsdInputStream
    	 * @param xmlInputStream
    	 * @return true 通过校验, false xml有语法错误或未通过校验
    	 * @throws SAXException 校验过程出错
    	 * @throws IOException 校验过程出错
    	 */
    	public static boolean isValid(InputStream xsdInputStream, InputStream xmlInputStream) throws SAXException, IOException {
    	    return isValid(xsdInputStream, xmlInputStream, null);
    	}
    	
    	/**
    	 * 验证xml文档是否符合xsd校验
    	 * @param xsdInputStream
    	 * @param xml
    	 * @return true 通过校验, false xml有语法错误或未通过校验
    	 * @throws SAXException 校验过程出错
    	 * @throws IOException 校验过程出错
    	 */
    	public static boolean isValid(InputStream xsdInputStream, String xml) throws SAXException, IOException {
    	    return isValid(xsdInputStream, xml, null);
    	}
    	
    	/**
    	 * 验证xml文档是否符合xsd校验
    	 * @param xsdInputStream
    	 * @param xmlInputStream
    	 * @param errorHandler xml文档warning、error、fatalError的回调接口
    	 * @return true 由errorHandler的方法实现决定,false xml校验未通过
    	 * @throws SAXException 校验过程出错
    	 * @throws IOException 校验过程出错
    	 */
    	public static boolean isValid(InputStream xsdInputStream, InputStream xmlInputStream, ErrorHandler errorHandler) throws SAXException, IOException {
    	    Validator validator = initValidator(xsdInputStream);
    	    if (errorHandler != null) {
    	    	validator.setErrorHandler(errorHandler);
    		}
    	    
    	    return isValid(validator, xmlInputStream);
    	}
    	
    	/**
    	 * 验证xml文档是否符合xsd校验
    	 * @param xsdInputStream
    	 * @param xml
    	 * @param errorHandler xml文档warning、error、fatalError的回调接口
    	 * @return true 由errorHandler的方法实现决定,false xml校验未通过
    	 * @throws SAXException 校验过程出错
    	 * @throws IOException 校验过程出错
    	 */
    	public static boolean isValid(InputStream xsdInputStream, String xml, ErrorHandler errorHandler) throws SAXException, IOException {
    	    Validator validator = initValidator(xsdInputStream);
    	    if (errorHandler != null) {
    	    	validator.setErrorHandler(errorHandler);
    		}
    	    return isValid(validator, xml);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    说明

    1. 如果不传入 errorHandler 参数,则使用JDK默认的 DraconianErrorHandler,当xml严重错误时执行 fatalError 方法,当xml内容不符合xsd规则时执行 error 方法,此时都会抛出 SAXParseException 异常,由上面的 private static boolean isValid(Validator validator, InputStream xmlInputStream) throws IOException 方法捕获,返回false校验未通过;当校验通过时,不执行 error 方法和 fatalError 方法,不抛出 SAXParseException 异常,返回true。
    package com.sun.org.apache.xerces.internal.jaxp.validation;
    
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.SAXException;
    import org.xml.sax.SAXParseException;
    
    /**
     * {@link ErrorHandler} that throws all errors and fatal errors.
     *
     * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
     */
    final class DraconianErrorHandler implements ErrorHandler {
    
        /**
         * Singleton instance.
         */
        private static final DraconianErrorHandler ERROR_HANDLER_INSTANCE
            = new DraconianErrorHandler();
    
        private DraconianErrorHandler() {}
    
        /** Returns the one and only instance of this error handler. */
        public static DraconianErrorHandler getInstance() {
            return ERROR_HANDLER_INSTANCE;
        }
    
        /** Warning: Ignore. */
        public void warning(SAXParseException e) throws SAXException {
            // noop
        }
    
        /** Error: Throws back SAXParseException. */
        public void error(SAXParseException e) throws SAXException {
            throw e;
        }
    
        /** Fatal Error: Throws back SAXParseException. */
        public void fatalError(SAXParseException e) throws SAXException {
            throw e;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    1. 如果传入自定义的 errorHandler 参数,则使用自定义的 ErrorHandler。
      如:自定义的 XmlErrorHandler 类,当xml严重错误时执行 fatalError 方法,当xml内容不符合xsd规则时执行 error 方法,此时未抛出异常,而是将异常对象 SAXParseException 加入到对应的 List,上面的 private static boolean isValid(Validator validator, InputStream xmlInputStream) throws IOException 方法不能捕获 SAXParseException 异常,返回true;当捕获到 SAXParseException 异常时,表示校验程序出错,返回false。
      因此这里不能根据方法的返回值是true或false来判断是否校验通过。
    import java.util.ArrayList;
    import java.util.List;
    
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.SAXParseException;
    
    public class XmlErrorHandler implements ErrorHandler {
    
    	private List<SAXParseException> warningExceptions;
    	
    	private List<SAXParseException> errorExceptions;
    	
    	private List<SAXParseException> fatalErrorExceptions;
    
        public XmlErrorHandler() {
            this.warningExceptions = new ArrayList<>();
            this.errorExceptions = new ArrayList<>();
            this.fatalErrorExceptions = new ArrayList<>();
        }
    
        public List<SAXParseException> getWarningExceptions() {
    		return warningExceptions;
    	}
    
    	public List<SAXParseException> getErrorExceptions() {
    		return errorExceptions;
    	}
    
    	public List<SAXParseException> getFatalErrorExceptions() {
    		return fatalErrorExceptions;
    	}
    
    	@Override
        public void warning(SAXParseException exception) {
    		warningExceptions.add(exception);
        }
    
        @Override
        public void error(SAXParseException exception) {
        	errorExceptions.add(exception);
        }
    
        @Override
        public void fatalError(SAXParseException exception) {
        	fatalErrorExceptions.add(exception);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    使用

    public class JarUtils {
    	/**
    	 * 获取项目里的资源输入流
    	 * @param sourcePath 项目编译后classes目录下的文件路径, 如application.properties、com/xxx/util/JarUtils.class
    	 * @return null 如果未找到文件
    	 */
    	public static InputStream getResourceAsStream(String sourcePath) {
    		return JarUtils.class.getClassLoader().getResourceAsStream(sourcePath);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用JDK默认的 errorHandler

    public static void main(String[] args) throws SAXException, IOException {
    	String xml = "\r\n"
    			+ "\r\n"
    			+ "    student\r\n"
    			+ "    
    \r\n" + " 00001\r\n" + " New York\r\n" + "
    \r\n"
    + ""; InputStream xsdInputStream = JarUtils.getResourceAsStream("xmlschema/full-person.xsd"); if (xsdInputStream == null) { return; } try { boolean valid = isValid(xsdInputStream, xml); System.out.println("校验结果:" + valid); } finally { xsdInputStream.close(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用自定义的 errorHandler

    /**
     * 验证xml文档是否符合xsd校验
     * @param xsdPath
     * @param xml
     * @throws RuntimeException 校验程序出错或语法错误
     * @throws IllegalArgumentException 校验未通过
     */
    public static void validate(String xsdPath, String xml) {
    	InputStream xsdInputStream = JarUtils.getResourceAsStream(xsdPath);
    	if (xsdInputStream == null) {
    		throw new NullPointerException("未找到" + xsdPath + "校验文档");
    	}
    	try {
    		XmlErrorHandler errorHandler = new XmlErrorHandler();
    		try {
    			boolean valid = isValid(xsdInputStream, xml, errorHandler);
    			if (!valid) {
    				if (!errorHandler.getFatalErrorExceptions().isEmpty()) {
    					throw new IllegalArgumentException("xml:" + xml + "语法错误", errorHandler.getFatalErrorExceptions().get(0));
    				}
    				throw new RuntimeException("校验程序出错");
    			}
    		} catch (Exception e) {
    			throw new RuntimeException("校验程序出错", e);
    		}
    		if (!errorHandler.getErrorExceptions().isEmpty()) {
    			throw new IllegalArgumentException("xml:" + xml + "校验未通过", errorHandler.getErrorExceptions().get(0));
    		}
    	} finally {
    		try {
    			xsdInputStream.close();
    		} catch (IOException e) {
    		}
    	}
    }
    
    public static void main(String[] args) {
    	String xml = "\r\n"
    			+ "\r\n"
    			+ "    student\r\n"
    			+ "    
    \r\n" + " 00001\r\n" + " New York\r\n" + "
    \r\n"
    + ""; try { validate("xmlschema/full-person.xsd", xml); System.out.println("校验通过"); } catch (Exception e) { e.printStackTrace(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    参考文档

    https://www.baeldung.com/java-validate-xml-xsd

  • 相关阅读:
    Shell 函数
    基于深度学习的模糊认知图方法
    《Linux内核精通》笔记参考目录
    制造业小企业内部小程序简单设计
    解决SpringCloud的Gateway网关无法访问服务的静态资源
    构建实用的Flutter文件列表:从简到繁的完美演进
    约数——正约数个数求法及其原理,求N的正约数集合
    工业物联网解决方案:PLC数据上云
    有趣的 TCP 抢带宽行为
    Laravel框架中的目录结构都有什么作用?
  • 原文地址:https://blog.csdn.net/daodfs111/article/details/126745475