Spring集成 - XML Schema验证器 - 动态模式文件选择

时间:2015-09-02 22:43:27

标签: spring-integration xml-validation

我正在尝试使用Spring Integration <int-xml:validating-filter />实现XML验证。我跟随usage of spring integration's schema validator?中的讨论。问题陈述是相同的,但有一个额外的参数。而不是硬编码schema-location="xyz.xsd"中的值,而是我想为相应的传入xml或DOMSource输入动态选择适当的xsd文件。 我还跟着http://forum.spring.io/forum/spring-projects/integration/121115-dynamic-schema-location-for-xml-validating-filter-component 加里拉塞尔提到了

  

动态模式没有直接支持,但您可以提供   使用xml-validator属性定制XmlValidator(相互之间   独家与架构位置)   一旦您对您的文档进行了内省,就可以找到您想要的模式   验证,只需委托给已经验证的验证器   配置为针对该架构进行验证。

     

您可以使用XmlValidatorFactory创建每个验证器;看到了   XmlValidatingMessageSelector用于如何创建验证器   知道架构位置

由于评论可以追溯到2012年,现在是否有一种方法可以在Spring集成中通过动态选择适当的模式来验证输入xml?如果没有,任何人都可以提供一个如何实施的例子吗?

以下是我的spring集成配置:

<int:gateway id="applicationServiceGateway" service-interface="abc.IGateway"
  default-request-channel="applicationRequestChannel" default-reply-channel="applicationResponseChannel"
  error-channel="errorProcessingChannel" />

<int:chain id="serviceRequestValidation" input-channel="applicationRequestChannel" output-channel="responseChannel">
  <!-- How to do  -->
  <int-xml:validating-filter xml-validator="xmlValidator" 
                             schema-type="xml-schema" 
                             throw-exception-on-rejection="true" />
  <int:service-activator id="schematronValidationActivator" ref="schematronValidator" method="validate" />       
</int:chain>

<bean id="xmlValidator" class="abc.validator.DomSourceValidator" />

这是我定义的Validator类:

import org.springframework.xml.validation.ValidationErrorHandler;
import org.springframework.xml.validation.XmlValidator;
import org.xml.sax.SAXParseException;
public class DomSourceValidator implements XmlValidator {

    @Override
    public SAXParseException[] validate(Source source) throws IOException {
        /* How to implement this method? 
           Using XPath I can identify the root node from 'source' and then load
           the appropriate XSD file. But don't know how to proceed 
           or what should be 'return'(ed) from here. 
           Any example is much appreciated.
         */

        return null;
    }

    @Override
    public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException {
      // TODO Auto-generated method stub
      return null;
    }

}

使用Spring Integration实现XML验证器的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

自该评论以来没有任何变化。

正如我在那里所说,验证器需要使用XmlValidatorFactory为每个模式创建验证器;然后为每条消息调用特定的验证器;类似的东西:

String schema = determineSchema(source);
XmlValidator val = lookupValidatorForSchema(schema);
if (val == null) {
    // create a new one and add it to the map.
}
return val.validate(source);

答案 1 :(得分:0)

如果它有助于其他尝试做同样事情的人

根据Gary的建议,我通过动态识别输入XML然后选择适当的Schema文件来应用验证,推出了XmlValidator的实现。

以下是我的spring集成配置:

<int:gateway id="applicationServiceGateway" service-interface="abc.IGateway" default-request-channel="applicationRequestChannel" default-reply-channel="applicationResponseChannel" error-channel="errorProcessingChannel" />
    <int:chain id="serviceRequestValidation" input-channel="applicationRequestChannel" output-channel="responseChannel">
    <int-xml:validating-filter xml-validator="xmlValidator" 
                         schema-type="xml-schema" 
                         throw-exception-on-rejection="true" /> <!-- a MessageRejectedException is thrown in case validation fails -->
    <int:service-activator id="schematronValidationActivator" ref="schematronValidator" method="validate" />       
</int:chain>

<bean id="xmlValidator" class="abc.validator.DomSourceValidator">
    <constructor-arg>
        <map key-type="java.lang.String" value-type="java.lang.String">
            <entry key="OTA_AirAvailRQ"      value="common/schemas/FS_OTA_AirAvailRQ.xsd" />
            <entry key="OTA_AirBookModifyRQ" value="common/schemas/FS_OTA_AirBookModifyRQ.xsd" />
            <entry key="OTA_AirBookRQ"       value="common/schemas/FS_OTA_AirBookRQ.xsd" />
        </map>
    </constructor-arg>
</bean>

要演示我已使用OTA架构文件将地图构建为constructor-arg。映射key是来自网关的XML文件的根节点,value是xsd文件的位置;并形成key-value对地图。

请参阅下面的实现类,了解如何使用此映射来标识输入XML并应用验证。

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;
import org.springframework.xml.validation.ValidationErrorHandler;
import org.springframework.xml.validation.XmlValidator;
import org.springframework.xml.validation.XmlValidatorFactory;
import org.xml.sax.SAXParseException;

public class DomSourceValidator implements XmlValidator {

    private static final Log LOGGER = LogFactory.getLog(DomSourceValidator.class);

    private Map<String, String> schemaMap;
    private static Map<String, XmlValidator> validatorMap = new HashMap<>();

    public DomSourceValidator(Map<String, String> schemaMap) {
        this.schemaMap = schemaMap;
    }

    @PostConstruct
    private void init() throws IOException {
        LOGGER.info("Constructing Validators from schema resource list ...");
        Assert.notEmpty(schemaMap, "No schema resource map found");
        if (validatorMap.isEmpty()) {
            XmlValidator validator = null;
            for (Map.Entry<String, String> entry : schemaMap.entrySet()) {
                validator = createValidatorFromResourceUri(entry.getValue());
                validatorMap.put(entry.getKey(), validator);
            }
        }
    }

    @Override
    public SAXParseException[] validate(Source source) throws IOException {
        Assert.notNull(schemaMap, "No validator(s) defined");
        XmlValidator validator = lookupValidator(source);
        return validator.validate(source);
    }

    @Override
    public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException {
        // Skip implementation
        return null;
    }

    private XmlValidator lookupValidator(Source source) {
        String reqType = determineRequestType(source);
        LOGGER.info("Loading validator for type: " + reqType);
        XmlValidator xmlValidator = validatorMap.get(reqType);
        Assert.notNull(xmlValidator, "No validator found for type: " + reqType);
        return xmlValidator;
    }

    private String determineRequestType(Source source) {
        if (source instanceof DOMSource) {
            return ((DOMSource) source).getNode().getFirstChild().getNodeName();
        }
        return null;
    }

    private XmlValidator createValidatorFromResourceUri(String schemaResource) throws IOException {
        Assert.notNull(schemaResource);
        return XmlValidatorFactory.createValidator(new ClassPathResource(schemaResource), XmlValidatorFactory.SCHEMA_W3C_XML);
    }
}

初始化spring bean id="xmlValidator"后,@PostConstruct启动以使用资源URI中的XmlValidatorFactory创建Validator实例,以获得预先初始化的验证器。

如果出现验证错误,则会引发org.springframework.integration.MessageRejectedException: Message was rejected due to XML Validation errorsthrow-exception-on-rejection="true"中的参考<int-xml:validating-filter />)。

上述实现对我来说非常好。可以进一步自定义,或发布另一个版本以实现相同目的。

注意

除了使用<int-xml:validating-filter />之外,还可以使用<int:service-activator />中的<int-chain />,因为逻辑<int-xml:validating-filter />实际上并不执行任何过滤逻辑。但这符合目的。