如何捕获并差异化处理XSD补充约束的验证违规问题?
差异化处理客户自定义XSD约束的验证违规
核心思路
要区分原生XSD约束和客户添加的补充约束违规,关键是给客户的约束添加唯一标识的注解,再通过验证工具的自定义错误处理器识别这些标记,进而做差异化处理。以下是针对Xerces和Saxon的具体实现方案:
步骤1:给客户补充约束添加标记注解
要求客户在添加xs:fixed、xs:maxLength等约束时,附带自定义的xs:appinfo标记,示例如下:
<xs:element name="customerId"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="10"> <xs:annotation> <xs:appinfo>customer-custom-constraint</xs:appinfo> </xs:annotation> </xs:maxLength> </xs:restriction> </xs:simpleType> </xs:element>
方案1:使用Xerces实现差异化处理
Xerces允许通过自定义ErrorHandler拦截验证错误,并关联到对应的Schema组件,从而识别带标记的约束:
自定义ErrorHandler实现
import org.apache.xerces.xs.XSAnnotation; import org.apache.xerces.xs.XSStringList; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class CustomConstraintErrorHandler implements ErrorHandler { @Override public void warning(SAXParseException exception) throws SAXException { handleException(exception, false); } @Override public void error(SAXParseException exception) throws SAXException { handleException(exception, true); } @Override public void fatalError(SAXParseException exception) throws SAXException { handleException(exception, true); } private void handleException(SAXParseException exception, boolean isError) throws SAXException { // 从异常中获取关联的Schema组件 if (exception instanceof org.apache.xerces.impl.xs.XSValidationError) { org.apache.xerces.impl.xs.XSValidationError validationError = (org.apache.xerces.impl.xs.XSValidationError) exception; var schemaComponent = validationError.getXSObject(); // 检查组件是否带有客户自定义约束标记 if (schemaComponent != null) { XSAnnotation annotation = schemaComponent.getAnnotation(); if (annotation != null) { XSStringList appInfos = annotation.getAppInfos(); for (int i = 0; i < appInfos.getLength(); i++) { if ("customer-custom-constraint".equals(appInfos.item(i))) { // 差异化处理客户约束违规:单独记录、返回特定提示等 System.err.println("[客户自定义约束违规] " + exception.getMessage()); return; } } } } } // 原生XSD约束违规,按常规逻辑处理 if (isError) { throw exception; } else { System.err.println("[原生约束警告] " + exception.getMessage()); } } }
配置Xerces使用自定义ErrorHandler
import org.apache.xerces.parsers.DOMParser; import org.xml.sax.SAXException; import java.io.IOException; public class XercesValidationExample { public static void main(String[] args) throws IOException, SAXException { DOMParser parser = new DOMParser(); parser.setErrorHandler(new CustomConstraintErrorHandler()); // 启用XSD验证 parser.setFeature("http://xml.org/sax/features/validation", true); parser.setFeature("http://apache.org/xml/features/validation/schema", true); // 若使用XSD 1.1,启用对应特性 parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true); parser.setFeature("http://apache.org/xml/features/validation/schema-version", "1.1"); parser.parse("your-input.xml"); } }
方案2:使用Saxon实现差异化处理
Saxon提供ValidationListener接口,可拦截验证事件并关联到Schema节点,识别客户自定义约束:
自定义ValidationListener实现
import net.sf.saxon.lib.ValidationListener; import net.sf.saxon.s9api.NamespaceConstant; import net.sf.saxon.s9api.NodeInfo; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.type.ValidationFailure; public class CustomConstraintValidationListener implements ValidationListener { @Override public void reportValidationError(ValidationFailure failure, boolean isFatal) { // 获取违规对应的Schema约束节点 NodeInfo constraintNode = failure.getConstraintReference().getSchemaNode(); if (constraintNode != null) { // 检查约束节点是否带有自定义appinfo标记 NodeInfo annotation = constraintNode.selectChild(NodeKind.ELEMENT, "annotation", NamespaceConstant.SCHEMA).head(); if (annotation != null) { NodeInfo appInfo = annotation.selectChild(NodeKind.ELEMENT, "appinfo", NamespaceConstant.SCHEMA).head(); if (appInfo != null && "customer-custom-constraint".equals(appInfo.getStringValue().trim())) { // 差异化处理客户约束违规 System.err.println("[客户自定义约束违规] " + failure.getMessage()); return; } } } // 原生约束违规,按常规逻辑处理 if (isFatal) { throw new SaxonApiException(failure); } else { System.err.println("[原生约束违规] " + failure.getMessage()); } } }
配置Saxon使用自定义ValidationListener
import net.sf.saxon.s9api.*; import java.io.File; public class SaxonValidationExample { public static void main(String[] args) throws SaxonApiException { Processor processor = new Processor(true); SchemaManager schemaManager = processor.getSchemaManager(); // 加载XSD(自动识别1.0/1.1版本) schemaManager.load(new File("your-schema.xsd")); SchemaValidator validator = schemaManager.newSchemaValidator(); validator.setValidationListener(new CustomConstraintValidationListener()); // 加载待验证的XML DocumentBuilder builder = processor.newDocumentBuilder(); XdmNode xmlDoc = builder.build(new File("your-input.xml")); // 执行验证 validator.validate(xmlDoc); } }
注意事项
- 需确保客户严格遵循注解标记规则,否则无法区分约束类型
- XSD 1.1的额外特性(如
xs:assert断言)也可采用相同标记方式处理 - 差异化处理逻辑可根据需求调整(比如跳过某些客户约束、生成特定格式的错误报告等)
内容的提问来源于stack exchange,提问作者J. Nicholas
相关产品推荐
相关产品推荐

