You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获并差异化处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:10:33