XML 支持 - 处理 XML 有效负载

Spring Integration 的 XML 支持通过以下组件扩展了 Spring Integration 的核心:

您需要将此依赖项包含到您的项目中:

Maven
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-xml</artifactId>
    <version>5.5.13</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-xml:5.5.13"

这些组件使得在 Spring Integration 中处理 XML 消息更加简单。消息传递组件使用以多种格式表示的 XML,包括java.lang.Stringorg.w3c.dom.Documentjavax.xml.transform.Source. 但是,在需要 DOM 表示的情况下(例如,为了评估 XPath 表达式),String有效负载将转换为所需的类型,然后再转换回String. DocumentBuilder如果您不提供一个实例,则需要一个实例的组件会创建一个命名空间感知实例。当您需要更好地控制文档创建时,您可以提供适当配置的DocumentBuilder.

命名空间支持

Spring Integration XML 模块中的所有组件都提供命名空间支持。为了启用命名空间支持,您需要导入 Spring Integration XML 模块的模式。以下示例显示了一个典型设置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:int="http://www.springframework.org/schema/integration"
  xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration
    https://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/xml
    https://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd">
</beans>

XPath 表达式

Spring Integration XML 模块中的许多组件都使用 XPath 表达式。这些组件中的每一个要么引用已定义为顶级元素的 XPath 表达式,要么使用嵌套<xpath-expression/>元素。

所有形式的 XPath 表达式都会创建一个XPathExpression使用 Spring 的org.springframework.xml.xpath.XPathExpressionFactory。创建 XPath 表达式时,将使用类路径上可用的最佳 XPath 实现(JAXP 1.3+ 或 Jaxen,首选 JAXP)。

在内部,Spring Integration 使用 Spring Web Services 项目 ( https://www.spring.io/spring-ws ) 提供的 XPath 功能。具体来说,我们使用 Spring Web Services XML 模块 (spring-xml-xxxjar)。如需更深入的了解,请参阅https://docs.spring.io/spring-ws/docs/current/reference/#xpath上的相应文档。

以下是该元素所有可用配置参数的概述xpath-expression: 以下清单显示了该xpath-expression元素的可用属性:

<int-xml:xpath-expression expression="" (1)
          id=""                         (2)
          namespace-map=""              (3)
          ns-prefix=""                  (4)
          ns-uri="">                    (5)
    <map></map>                         (6)
</int-xml:xpath-expression>
1 定义 XPath 表达式。必需的。
2 底层 bean 定义的标识符。它是 的一个实例org.springframework.xml.xpath.XPathExpression。可选的。
3 对包含命名空间的映射的引用。map 的 key 定义命名空间前缀,map 的 value 设置命名空间 URI。map同时指定此属性和元素或ns-prefixand属性是无效的ns-uri。可选的。
4 允许您将命名空间前缀直接设置为 XPath 表达式元素的属性。如果设置ns-prefix,则还必须设置ns-uri属性。可选的。
5 允许您直接将命名空间 URI 设置为 XPath 表达式元素的属性。如果设置ns-uri,则还必须设置ns-prefix属性。可选的。
6 定义一个包含命名空间的映射。只map允许一个子元素。map 的 key 定义命名空间前缀,map 的 value 设置命名空间 URI。map同时指定此元素和属性或设置ns-prefix和属性是无效的ns-uri。可选的。
为 XPath 表达式提供命名空间(可选)

对于 XPath 表达式元素,您可以提供名称空间信息作为配置参数。您可以使用以下选项之一来定义命名空间:

  • 使用namespace-map属性引用地图

  • 使用map子元素提供命名空间映射

  • 指定ns-prefixns-uri属性

这三个选项都是互斥的。只能设置一个选项。

以下示例显示了使用 XPath 表达式的几种不同方法,包括用于设置前面提到的 XML 命名空间的选项:

<int-xml:xpath-filter id="filterReferencingXPathExpression"
                      xpath-expression-ref="refToXpathExpression"/>

<int-xml:xpath-expression id="refToXpathExpression" expression="/name"/>

<int-xml:xpath-filter id="filterWithoutNamespace">
    <int-xml:xpath-expression expression="/name"/>
</int-xml:xpath-filter>

<int-xml:xpath-filter id="filterWithOneNamespace">
    <int-xml:xpath-expression expression="/ns1:name"
                              ns-prefix="ns1" ns-uri="www.example.org"/>
</int-xml:xpath-filter>

<int-xml:xpath-filter id="filterWithTwoNamespaces">
    <int-xml:xpath-expression expression="/ns1:name/ns2:type">
        <map>
            <entry key="ns1" value="www.example.org/one"/>
            <entry key="ns2" value="www.example.org/two"/>
        </map>
    </int-xml:xpath-expression>
</int-xml:xpath-filter>

<int-xml:xpath-filter id="filterWithNamespaceMapReference">
    <int-xml:xpath-expression expression="/ns1:name/ns2:type"
                              namespace-map="defaultNamespaces"/>
</int-xml:xpath-filter>

<util:map id="defaultNamespaces">
    <util:entry key="ns1" value="www.example.org/one"/>
    <util:entry key="ns2" value="www.example.org/two"/>
</util:map>
将 XPath 表达式与默认命名空间一起使用

使用默认命名空间时,您可能会遇到行为与预期不同的情况。假设我们有以下 XML 文档(表示两本书的顺序):

<?xml version="1.0" encoding="UTF-8"?>
<order>
    <orderItem>
        <isbn>0321200683</isbn>
        <quantity>2</quantity>
    </orderItem>
    <orderItem>
        <isbn>1590596439</isbn>
        <quantity>1</quantity>
    </orderItem>
</order>

本文档未声明命名空间。因此,应用以下 XPath 表达式按预期工作:

<int-xml:xpath-expression expression="/order/orderItem" />

您可能期望相同的表达式也适用于以下 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<order xmlns="http://www.example.org/orders">
	<orderItem>
		<isbn>0321200683</isbn>
		<quantity>2</quantity>
	</orderItem>
	<orderItem>
		<isbn>1590596439</isbn>
		<quantity>1</quantity>
	</orderItem>
</order>

前面的示例看起来与前面的示例完全相同,但声明了一个默认命名空间。

但是,在这种情况下,前面的 XPath 表达式 ( /order/orderItem) 会失败。

为了解决这个问题,您必须通过设置ns-prefixandns-uri属性或设置namespace-map属性来提供命名空间前缀和命名空间 URI。命名空间 URI 必须与 XML 文档中声明的命名空间相匹配。在前面的示例中,即http://www.example.org/orders.

但是,您可以任意选择命名空间前缀。事实上,提供一个空字符串确实有效。(但是,null 是不允许的。)在命名空间前缀由空字符串组成的情况下,您的 Xpath 表达式必须使用冒号 (":") 来指示默认命名空间。如果省略冒号,则 XPath 表达式不匹配。以下 XPath 表达式与前面示例中的 XML 文档匹配:

<int-xml:xpath-expression expression="/:order/:orderItem"
    ns-prefix="" ns-uri="https://www.example.org/prodcuts"/>

您还可以提供任何其他任意选择的命名空间前缀。以下 XPath 表达式(使用myorder命名空间前缀)也匹配:

<int-xml:xpath-expression expression="/myorder:order/myorder:orderItem"
    ns-prefix="myorder" ns-uri="https://www.example.org/prodcuts"/>

命名空间 URI 是真正重要的信息,而不是前缀。https://github.com/jaxen-xpath/jaxen[Jaxen] 很好的总结了一点:

在 XPath 1.0 中,所有不带前缀的名称都是不合格的。不要求 XPath 表达式中使用的前缀与被查询文档中使用的前缀相同。只有命名空间 URI 需要匹配,而不是前缀。

转换 XML 负载

本节介绍如何转换 XML 有效负载

将 Transformer 配置为 Bean

本节将解释以下转换器的工作原理以及如何将它们配置为 bean:

所有 XML 转换器都扩展了AbstractTransformerAbstractPayloadTransformer,因此实现了Transformer. 在 Spring Integration 中将 XML 转换器配置为 bean 时,通常会Transformer配置MessageTransformingHandler. 这使变压器可以用作端点。最后,我们讨论命名空间支持,它允许将转换器配置为 XML 中的元素。

解组变压器

通过使用Spring OXMUnmarshallingTransformer的实现,可以对 XML进行解组。Spring 的 Object/XML Mapping 支持提供了几种使用JAXBCastorJiBX等支持编组和解组的实现。解组器需要一个. 如果消息负载不是 的实例,仍会尝试转换。目前,支持、和有效负载。要创建到 a 的自定义转换,您可以注入 a 的实现。Source UnmarshallerSourceSourceStringFilebyte[]org.w3c.dom.DocumentSourceSourceFactory

如果您没有显式设置 a SourceFactory,则默认情况下,该属性UnmarshallingTransformer设置为 a DomSourceFactory

从 5.0 版开始,UnmarshallingTransformer还支持org.springframework.ws.mime.MimeMessage作为传入的有效负载。WebServiceMessage当我们通过 SOAP 接收带有 MTOM 附件的原始数据时,这会很有用。有关详细信息,请参阅MTOM 支持

以下示例显示了如何定义解组转换器:

<bean id="unmarshallingTransformer" class="o.s.i.xml.transformer.UnmarshallingTransformer">
    <constructor-arg>
        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <property name="contextPath" value="org.example" />
        </bean>
    </constructor-arg>
</bean>
使用MarshallingTransformer

MarshallingTransformer允许使用 Spring OXM 将对象图转换为XML Marshaller。默认情况下,MarshallingTransformer返回一个DomResult. 但是,您可以通过配置替代项来控制结果类型ResultFactory,例如StringResultFactory. 在许多情况下,将有效负载转换为另一种 XML 格式会更方便。为此,请配置一个ResultTransformer. Spring 集成提供了两种实现,一种String转换为Document. 以下示例配置了一个可转换为文档的编组转换器:

<bean id="marshallingTransformer" class="o.s.i.xml.transformer.MarshallingTransformer">
    <constructor-arg>
        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <property name="contextPath" value="org.example"/>
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
    </constructor-arg>
</bean>

默认情况下,MarshallingTransformer将有效负载对象传递给Marshaller. 但是,如果将其布尔extractPayload属性设置为false,则将整个Message实例传递给Marshaller。这对于接口的某些自定义实现可能很有用,但通常,当您委托给任何各种实现Marshaller时,有效负载是编组的适当源对象。Marshaller

XsltPayloadTransformer

使用可扩展样式表语言转换(XSLT)XsltPayloadTransformer转换 XML 有效负载。转换器的构造函数需要传入ResourceTemplates的实例。传入实例允许对用于创建模板实例的对象进行更大的配置。TemplatesTransformerFactory

与一样UnmarshallingTransformerXsltPayloadTransformerSource. 因此,如果消息负载不是 的实例Source,仍会尝试转换。 直接支持有效载荷StringDocument

要创建到 a 的自定义转换Source,您可以注入 a 的实现SourceFactory

如果 aSourceFactory没有显式设置,则XsltPayloadTransformer默认情况下将属性设置为 a DomSourceFactory

默认情况下,XsltPayloadTransformer创建带有Result有效负载的消息,类似于XmlPayloadMarshallingTransformer. 您可以通过提供 aResultFactory或 a来自定义它ResultTransformer

以下示例配置一个用作 XSLT 有效负载转换器的 bean:

<bean id="xsltPayloadTransformer" class="o.s.i.xml.transformer.XsltPayloadTransformer">
  <constructor-arg value="classpath:org/example/xsl/transform.xsl"/>
  <constructor-arg>
    <bean class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
  </constructor-arg>
</bean>

从 Spring Integration 3.0 开始,您可以使用构造函数参数指定转换器工厂类名称。您可以transformer-factory-class在使用命名空间时使用属性来执行此操作。

使用ResultTransformer实现

theMarshallingTransformer和 the都XsltPayloadTransformer可以让你指定一个ResultTransformer. 因此,如果编组或 XSLT 转换返回 a Result,您还可以选择使用 aResultTransformer将其转换Result为另一种格式。Spring Integration 提供了两种具体的ResultTransformer实现:

默认情况下,MarshallingTransformer总是返回一个Result. 通过指定 a ResultTransformer,您可以自定义返回的有效负载类型。

的行为稍微复杂一些XsltPayloadTransformer。默认情况下,如果输入有效负载是的实例或String属性被忽略。DocumentresultTransformer

但是,如果输入有效负载是 aSource或任何其他类型,resultTransformer则应用该属性。此外,您可以将alwaysUseResultFactory属性设置为true,这也会导致使用指定的属性resultTransformer

有关更多信息和示例,请参阅命名空间配置和结果转换器

XML 转换器的命名空间支持

在 Spring Integration XML 命名空间中提供了对所有 XML 转换器的命名空间支持,前面显示了一个模板。根据提供的输入通道的类型,对转换器的命名空间支持创建一个EventDrivenConsumer或的实例。PollingConsumer命名空间支持旨在通过允许创建使用一个元素的端点和转换器来减少 XML 配置的数量。

使用UnmarshallingTransformer

的命名空间支持UnmarshallingTransformer如下所示。由于命名空间创建了一个端点实例而不是一个转换器,因此您可以在元素中嵌套一个轮询器来控制输入通道的轮询。以下示例显示了如何执行此操作:

<int-xml:unmarshalling-transformer id="defaultUnmarshaller"
    input-channel="input" output-channel="output"
    unmarshaller="unmarshaller"/>

<int-xml:unmarshalling-transformer id="unmarshallerWithPoller"
    input-channel="input" output-channel="output"
    unmarshaller="unmarshaller">
    <int:poller fixed-rate="2000"/>
<int-xml:unmarshalling-transformer/>
用一个MarshallingTransformer

编组转换器的命名空间支持需要一个input-channel、一个output-channel和一个对 a 的引用marshaller。您可以使用可选result-type属性来控制创建的结果类型。有效值为StringResultor DomResult(默认值)。以下示例配置编组转换器:

<int-xml:marshalling-transformer
     input-channel="marshallingTransformerStringResultFactory"
     output-channel="output"
     marshaller="marshaller"
     result-type="StringResult" />

<int-xml:marshalling-transformer
    input-channel="marshallingTransformerWithResultTransformer"
    output-channel="output"
    marshaller="marshaller"
    result-transformer="resultTransformer" />

<bean id="resultTransformer" class="o.s.i.xml.transformer.ResultToStringTransformer"/>

如果提供的结果类型不够用,您可以提供对自定义实现的引用,作为使用属性设置属性ResultFactory的替代方法。和属性是互斥的。result-typeresult-factoryresult-typeresult-factory

在内部, theStringResultDomResultresult 类型由ResultFactory实现表示:StringResultFactoryDomResultFactory
使用XsltPayloadTransformer

命名空间支持XsltPayloadTransformer允许您传入一个Resource(为了创建Templates实例)或传入一个预先创建的Templates实例作为引用。与编组转换器一样,您可以通过指定result-factoryresult-type属性来控制结果输出的类型。当您需要在发送前转换结果时,您可以使用result-transformer属性来引用ResultTransformer.

如果您指定result-factoryresult-type属性,alwaysUseResultFactory则底层证券XsltPayloadTransformer的属性trueXsltPayloadTransformerParser.

以下示例配置了两个 XSLT 转换器:

<int-xml:xslt-transformer id="xsltTransformerWithResource"
    input-channel="withResourceIn" output-channel="output"
    xsl-resource="org/springframework/integration/xml/config/test.xsl"/>

<int-xml:xslt-transformer id="xsltTransformerWithTemplatesAndResultTransformer"
    input-channel="withTemplatesAndResultTransformerIn" output-channel="output"
    xsl-templates="templates"
    result-transformer="resultTransformer"/>

您可能需要访问Message数据(例如Message标题)以帮助进行转换。例如,您可能需要访问某些Message标头并将它们作为参数传递给转换器(例如,transformer.setParameter(..))。Spring Integration 提供了两种方便的方法来完成此操作,如以下示例所示:

<int-xml:xslt-transformer id="paramHeadersCombo"
    input-channel="paramHeadersComboChannel" output-channel="output"
    xsl-resource="classpath:transformer.xslt"
    xslt-param-headers="testP*, *foo, bar, baz">

    <int-xml:xslt-param name="helloParameter" value="hello"/>
    <int-xml:xslt-param name="firstName" expression="headers.fname"/>
</int-xml:xslt-transformer>

如果消息头名称与参数名称一对一匹配,则可以使用该xslt-param-headers属性。在其中,您可以使用通配符进行简单的模式匹配。它支持以下简单的模式样式:xxx*xxx*xxxxxx*yyy

您还可以使用该<xslt-param/>元素配置单个 XSLT 参数。在该元素上,您可以设置expression属性或value属性。该expression属性应该是任何有效的 SpEL 表达式,并且Message是表达式评估上下文的根对象。该value属性(与valueSpring bean 中的任何属性一样)允许您指定简单的标量值。您还可以使用属性占位符(例如${some.value})。因此,使用expressionandvalue属性,您可以将 XSLT 参数映射到 的任何可访问部分Message以及任何文字值。

从 Spring Integration 3.0 开始,您现在可以通过设置transformer-factory-class属性来指定转换器工厂类名称。

命名空间配置和结果转换器

我们在Using ResultTransformerImplementations中介绍了如何使用结果转换器。本节中的示例使用 XML 命名空间配置来说明几个特殊用例。首先,我们定义ResultTransformer,如以下示例所示:

<beans:bean id="resultToDoc" class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>

ResultTransformer接受 aStringResult或 aDOMResult作为输入并将输入转换为 a Document

现在我们可以声明转换器了,如下:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
    xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"/>

如果传入消息的有效负载类型为Source,则作为第一步,Result使用ResultFactory. 由于我们没有指定 a ResultFactory,所以使用默认值DomResultFactory,这意味着转换产生 a DomResult

然而,正如我们指定的 a ResultTransformer,它被使用并且产生的Message有效载荷是类型Document

指定的被或有效载荷ResultTransformer忽略。如果传入消息的有效负载类型为,则 XSLT 转换后的有效负载为. 类似地,如果传入消息的有效负载类型为,则 XSLT 转换后的有效负载为“文档”。 StringDocumentStringStringDocument

如果消息负载不是 a Source、 aString或 a Document,作为后备选项,我们会尝试使用 default 创建一个`Source` SourceFactory。由于我们没有SourceFactory通过使用source-factory属性显式指定 a,因此使用默认值DomSourceFactory。如果成功,则执行 XSLT 转换,就好像负载是 typeSource一样,如前几段所述。

DomSourceFactory支持 从DOMSourcea Document、 aFileString有效负载创建 a。

下一个转换器声明添加一个用作其值的result-type属性。StringResult内部result-type由 表示StringResultFactoryStringResultFactory因此,您还可以通过使用属性添加对 a 的引用result-factory,这将是相同的。以下示例显示了转换器声明:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
		xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"
		result-type="StringResult"/>

因为我们使用 a ResultFactoryalwaysUseResultFactory所以类的属性XsltPayloadTransformer被隐式设置为true。因此,使用了引用ResultToDocumentTransformer

因此,如果您转换类型为 的有效负载String,则生成的有效负载为 类型Document

XsltPayloadTransformer<xsl:output method="text"/>

<xsl:output method="text"/>告诉 XSLT 模板仅从输入源生成文本内容。在这种特殊情况下,我们没有理由使用DomResult. 因此,XsltPayloadTransformer默认为StringResultif底层调用的输出属性返回。此强制执行独立于入站有效负载类型。此行为仅在您为组件设置 if属性或属性时可用。methodjavax.xml.transform.Transformertextresult-typeresult-factory<int-xml:xslt-transformer>

使用 XPath 转换 XML 消息

在消息转换方面,XPath 是转换具有 XML 有效负载的消息的好方法。您可以通过使用<xpath-transformer/>元素定义 XPath 转换器来做到这一点。

简单的 XPath 转换

考虑以下变压器配置:

<int-xml:xpath-transformer input-channel="inputChannel" output-channel="outputChannel"
      xpath-expression="/person/@name" />

还要考虑以下几点Message

Message<?> message =
  MessageBuilder.withPayload("<person name='John Doe' age='42' married='true'/>").build();

在将此消息发送到“inputChannel”之后,之前配置的 XPath 转换器将此 XML 消息转换为Message具有“John Doe”有效负载的简单消息,所有这些都基于xpath-expression属性中指定的简单 XPath 表达式。

XPath 还允许您将提取的元素简单地转换为所需的类型。有效的返回类型在接口中定义javax.xml.xpath.XPathConstants并遵循javax.xml.xpath.XPath接口指定的转换规则。

以下常量由XPathConstants类定义:BOOLEANDOM_OBJECT_MODELNODENODESETNUMBERSTRING

evaluation-type您可以使用元素的属性来配置所需的类型<xpath-transformer/>,如以下示例所示(两次):

<int-xml:xpath-transformer input-channel="numberInput" xpath-expression="/person/@age"
                           evaluation-type="NUMBER_RESULT" output-channel="output"/>

<int-xml:xpath-transformer input-channel="booleanInput"
                           xpath-expression="/person/@married = 'true'"
                           evaluation-type="BOOLEAN_RESULT" output-channel="output"/>

节点映射器

如果您需要为 XPath 表达式提取的节点提供自定义映射,您可以提供对实现的引用(实现用于基于每个节点映射对象org.springframework.xml.xpath.NodeMapper的接口)。要提供对 a 的引用,您可以使用该属性,如以下示例所示:XPathOperationsNodeNodeMappernode-mapper

<int-xml:xpath-transformer input-channel="nodeMapperInput" xpath-expression="/person/@age"
                           node-mapper="testNodeMapper" output-channel="output"/>

以下示例显示了NodeMapper与前面示例一起使用的实现:

class TestNodeMapper implements NodeMapper {
  public Object mapNode(Node node, int nodeNum) throws DOMException {
    return node.getTextContent() + "-mapped";
  }
}

XML 负载转换器

您还可以使用 的实现org.springframework.integration.xml.XmlPayloadConverter来提供更精细的转换。以下示例显示了如何定义一个:

<int-xml:xpath-transformer input-channel="customConverterInput"
                           output-channel="output" xpath-expression="/test/@type"
                           converter="testXmlPayloadConverter" />

以下示例显示了XmlPayloadConverter与前面示例一起使用的实现:

class TestXmlPayloadConverter implements XmlPayloadConverter {
  public Source convertToSource(Object object) {
    throw new UnsupportedOperationException();
  }
  //
  public Node convertToNode(Object object) {
    try {
      return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
          new InputSource(new StringReader("<test type='custom'/>")));
    }
    catch (Exception e) {
      throw new IllegalStateException(e);
    }
  }
  //
  public Document convertToDocument(Object object) {
    throw new UnsupportedOperationException();
  }
}

如果您不提供此参考,DefaultXmlPayloadConverter则使用 。在大多数情况下应该就足够了,因为它可以从NodeDocumentSourceFileStringInputStream、 和byte[]有效负载转换。如果您需要扩展该默认实现的功能,则上游Transformer可能比在此处提供对该策略的自定义实现的引用更好。

拆分 XML 消息

XPathMessageSplitter支持带有StringDocument负载的消息。拆分器使用提供的 XPath 表达式将有效负载拆分为多个节点。默认情况下,这会导致每个Node实例成为新消息的有效负载。当每条消息应该是 时Document,您可以设置createDocuments标志。在String传入有效负载的地方,有效负载被转换然后拆分,然后再转换回多个String消息。XPath 拆分器实现MessageHandler并因此应与适当的端点一起配置(请参阅以下示例之后的名称空间支持示例以获取更简单的配置替代方案)。以下示例配置一个使用 的 bean XPathMessageSplitter

<bean id="splittingEndpoint"
      class="org.springframework.integration.endpoint.EventDrivenConsumer">
    <constructor-arg ref="orderChannel" />
    <constructor-arg>
        <bean class="org.springframework.integration.xml.splitter.XPathMessageSplitter">
            <constructor-arg value="/order/items" />
            <property name="documentBuilder" ref="customisedDocumentBuilder" />
            <property name="outputChannel" ref="orderItemsChannel" />
        </bean>
    </constructor-arg>
</bean>

XPath 拆分器命名空间支持允许您创建具有输入通道和输出通道的消息端点,如以下示例所示:

<!-- Split the order into items and create a new message for each item node -->
<int-xml:xpath-splitter id="orderItemSplitter"
                       input-channel="orderChannel"
                       output-channel="orderItemsChannel">
    <int-xml:xpath-expression expression="/order/items"/>
</int-xml:xpath-splitter>

<!-- Split the order into items, create a new document for each item-->
<int-xml:xpath-splitter id="orderItemDocumentSplitter"
                       input-channel="orderChannel"
                       output-channel="orderItemsChannel"
                       create-documents="true">
    <int-xml:xpath-expression expression="/order/items"/>
    <int:poller fixed-rate="2000"/>
</int-xml:xpath-splitter>

从版本 4.2 开始,当请求不是类型时,会XPathMessageSplitter公开实例的outputProperties(例如OutputKeys.OMIT_XML_DECLARATION)属性。以下示例定义了一个属性并将其与该属性一起使用:javax.xml.transform.Transformerpayloadorg.w3c.dom.Nodeoutput-properties

<util:properties id="outputProperties">
	<beans:prop key="#{T (javax.xml.transform.OutputKeys).OMIT_XML_DECLARATION}">yes</beans:prop>
</util:properties>

<xpath-splitter input-channel="input"
             output-properties="outputProperties">
    <xpath-expression expression="/orders/order"/>
</xpath-splitter>

从 开始version 4.2,将选项XPathMessageSplitter公开为标志(默认为)。这允许下游流中拆分节点的“流式传输”。将模式设置为 时,每个节点都会在迭代时进行转换。当 时,首先转换所有条目,然后拆分节点开始发送到输出通道。(您可以将区别视为“转换、发送、转换、发送”与“转换、转换、发送、发送”。)有关更多信息,请参阅拆分器iteratorbooleantrueiteratortruefalse

使用 XPath 路由 XML 消息

与基于 SpEL 的路由器类似,Spring Integration 提供对基于 XPath 表达式的消息路由的支持,这使您可以创建具有输入通道但没有输出通道的消息端点。相反,一个或多个输出通道是动态确定的。以下示例显示了如何创建这样的路由器:

<int-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/order/type"/>
</int-xml:xpath-router>
有关路由器之间通用属性的概述,请参阅通用路由器参数

在内部,XPath 表达式被评估为类型NODESET并转换为List<String>表示通道名称的 a。通常,这样的列表包含单个频道名称。但是,根据 XPath 表达式的结果,如果 XPath 表达式返回多个值,XPath 路由器也可以具有收件人列表路由器的特征。在这种情况下,List<String>包含多个频道名称。因此,消息被发送到列表中的所有通道。

因此,假设传递给以下路由器配置的 XML 文件包含许多responder表示通道名称的子元素,则消息将发送到所有这些通道:

<!-- route the order to all responders-->
<int-xml:xpath-router id="responderRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/request/responders"/>
</int-xml:xpath-router>

如果返回值不直接表示通道名称,您可以指定其他映射参数以将这些返回值映射到实际通道名称。例如,如果/request/responders表达式产生两个值 (responderAresponderB),但您不想将响应者名称与通道名称耦合,则可以提供额外的映射配置,如下所示:

<!-- route the order to all responders-->
<int-xml:xpath-router id="responderRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/request/responders"/>
    <int-xml:mapping value="responderA" channel="channelA"/>
    <int-xml:mapping value="responderB" channel="channelB"/>
</int-xml:xpath-router>

如前所述,XPath 表达式的默认评估类型是NODESET,它被转换为List<String>通道名称,它可以处理单通道场景以及多通道场景。

尽管如此,某些 XPath 表达式可能String从一开始就评估为类型。例如,考虑以下 XPath 表达式:

name(./node())

此表达式返回根节点的名称。如果使用默认评估类型NODESET,则会导致异常。

对于这些场景,您可以使用该evaluate-as-string属性来管理评估类型。FALSE默认情况下。但是,如果将其设置为TRUEString则使用评估类型。

XPath 1.0 指定了 4 种数据类型:

  • 节点集

  • 字符串

  • 数字

  • 布尔值

当 XPath 路由器使用可选evaluate-as-string属性计算表达式时,返回值由string()函数确定,如 XPath 规范中所定义。这意味着,如果表达式选择多个节点,则返回第一个节点的字符串值。

有关详细信息,请参阅:

比如我们要根据根节点的名字进行路由,可以使用如下配置:

<int-xml:xpath-router id="xpathRouterAsString"
        input-channel="xpathStringChannel"
        evaluate-as-string="true">
    <int-xml:xpath-expression expression="name(./node())"/>
</int-xml:xpath-router>

XML 负载转换器

对于 XPath 路由器,您还可以指定要在 XPath 评估之前转换有效负载时使用的转换器。因此,XPath 路由器支持XmlPayloadConverter策略的自定义实现,并且当在 XML 中配置xpath-router元素时,可以通过converter属性提供对此类实现的引用。

如果未明确提供此引用,DefaultXmlPayloadConverter则使用 。在大多数情况下应该足够了,因为它可以从 Node、Document、Source、File 和 String 类型的负载转换。如果您需要扩展该默认实现的功能,那么在大多数情况下,上游 Transformer 通常是更好的选择,而不是在此处提供对该策略的自定义实现的引用。

XPath 标头丰富器

XPath 标头扩充器定义了标头扩充器消息转换器,它根据消息有效负载评估 XPath 表达式并将评估结果插入到消息头中。

以下清单显示了所有可用的配置参数:

<int-xml:xpath-header-enricher default-overwrite="true"    (1)
                               id=""                       (2)
                               input-channel=""            (3)
                               output-channel=""           (4)
                               should-skip-nulls="true">   (5)
    <int:poller></int:poller>                              (6)
    <int-xml:header name=""                                (7)
                    evaluation-type="STRING_RESULT"        (8)
                    header-type="int"                      (9)
                    overwrite="true"                       (10)
                    xpath-expression=""                    (11)
                    xpath-expression-ref=""/>              (12)
</int-xml:xpath-header-enricher>
1 指定是否覆盖现有标头值的默认布尔值。这仅对不提供自己的“覆盖”属性的子元素生效。如果不设置'default-overwrite' 属性,则指定的标头值不会覆盖任何具有相同标头名称的现有值。可选的。
2 底层 bean 定义的 ID。可选的。
3 此端点的接收消息通道。可选的。
4 将丰富消息发送到的通道。可选的。
5 指定是否应跳过空值,例如可能从表达式评估返回的值。默认值为true。如果空值应该触发相应标头的删除,请将其设置为false. 可选的。
6 与标题丰富器一起使用的轮询器。可选的。
7 要丰富的标头的名称。强制的。
8 XPath 评估预期的结果类型。如果您没有设置header-type属性,则这是标头值的类型。允许使用以下值:BOOLEAN_RESULTSTRING_RESULTNUMBER_RESULTNODE_RESULTNODE_LIST_RESULT。如果未设置,则在内部默认为XPathEvaluationType.STRING_RESULT. 可选的。
9 标头值类型的完全限定类名。XPath 求值的结果通过 转换为这种类型ConversionService。例如,这允许将 a NUMBER_RESULT(a double) 转换为Integer. 该类型可以声明为原始类型(例如int),但结果始终是等效的包装类(例如Integer)。有效负载类型转换ConversionService中讨论的相同集成用于转换,因此通过向服务添加自定义转换器来支持转换为自定义类型。可选的。
10 布尔值,指示此标头值是否应覆盖现有的同名标头值(如果输入中已存在)Message
11 XPath 表达式为String. 您必须设置此属性 或xpath-expression-ref,但不能同时设置。
12 XPath 表达式引用。您必须设置此属性 或xpath-expression,但不能同时设置。

使用 XPath 过滤器

该组件定义了一个基于 XPath 的消息过滤器。在内部,此组件使用MessageFilter包装了AbstractXPathMessageSelector.

有关详细信息,请参阅过滤器

要使用 XPath 过滤器,您至少必须通过声明xpath-expression元素或通过在xpath-expression-ref属性中引用 XPath 表达式来提供 XPath 表达式。

如果提供的 XPath 表达式计算为一个boolean值,则不需要其他配置参数。但是,如果 XPath 表达式的计算结果为 a String,则应设置与match-value计算结果匹配的属性。

match-type有三个选项:

  • exact: 对应equalsjava.lang.String。底层实现使用StringValueTestXPathMessageSelector

  • case-insensitive: 对应equals-ignore-casejava.lang.String。底层实现使用StringValueTestXPathMessageSelector

  • regex: 匹配操作一java.lang.String。底层实现使用RegexTestXPathMessageSelector

当提供 'regex' 的 'match-type' 值时,match-value属性提供的值必须是有效的正则表达式。

以下示例显示了xpath-filter元素的所有可用属性:

<int-xml:xpath-filter discard-channel=""                      (1)
                      id=""                                   (2)
                      input-channel=""                        (3)
                      match-type="exact"                      (4)
                      match-value=""                          (5)
                      output-channel=""                       (6)
                      throw-exception-on-rejection="false"    (7)
                      xpath-expression-ref="">                (8)
    <int-xml:xpath-expression ... />                          (9)
    <int:poller ... />                                        (10)
</int-xml:xpath-filter>
1 您希望将被拒绝的消息发送到的消息通道。可选的。
2 底层 bean 定义的 ID。可选的。
3 此端点的接收消息通道。可选的。
4 在 XPath 评估结果和match-value. 默认值为exact. 可选的。
5 要与 XPath 评估结果匹配的字符串值。如果不设置此属性,XPath 评估必须产生一个布尔结果。可选的。
6 与过滤条件匹配的消息被分派到的通道。可选的。
7 默认情况下,此属性设置为false并且被拒绝的消息(与过滤条件不匹配的消息)被静默丢弃。但是,如果设置为true,消息拒绝会导致错误条件和异常被上游传播到调用者。可选的。
8 对要计算的 XPath 表达式实例的引用。
9 此子元素设置要计算的 XPath 表达式。如果不包含此元素,则必须设置xpath-expression-ref属性。此外,您只能包含一个xpath-expression元素。
10 与 XPath 过滤器一起使用的轮询器。可选的。

#xpath SpEL 函数

Spring Integration 从 3.0 版开始,提供了内置的#xpathSpEL 函数,该函数调用XPathUtils.evaluate(…​)静态方法。此方法委托给org.springframework.xml.xpath.XPathExpression. 以下清单显示了一些使用示例:

<transformer expression="#xpath(payload, '/name')"/>

<filter expression="#xpath(payload, headers.xpath, 'boolean')"/>

<splitter expression="#xpath(payload, '//book', 'document_list')"/>

<router expression="#xpath(payload, '/person/@age', 'number')">
    <mapping channel="output1" value="16"/>
    <mapping channel="output2" value="45"/>
</router>

还支持第三个可选参数,#xpath()用于转换 XPath 评估的结果。它可以是字符串常量(stringbooleannumbernode和)之一或node_list实例。默认情况下,SpEL 函数返回XPath 评估的表示。document_listorg.springframework.xml.xpath.NodeMapper#xpathString

要启用#xpathSpEL 功能,您可以将 添加spring-integration-xml.jar到类路径中。您无需声明 Spring Integration XML 命名空间中的任何组件。

有关详细信息,请参阅“` Spring 表达式语言 (SpEL)

XML 验证过滤器

XML 验证过滤器允许您根据提供的模式实例验证传入消息。支持以下模式类型:

验证失败的消息可以被静默丢弃或转发到可定义的discard-channel. 此外,您可以配置此过滤器以在验证失败时抛出Exception异常。

以下清单显示了所有可用的配置参数:

<int-xml:validating-filter discard-channel=""                    (1)
                           id=""                                 (2)
                           input-channel=""                      (3)
                           output-channel=""                     (4)
                           schema-location=""                    (5)
                           schema-type="xml-schema"              (6)
                           throw-exception-on-rejection="false"  (7)
                           xml-converter=""                      (8)
                           xml-validator="">                     (9)
    <int:poller .../>                                            (10)
</int-xml:validating-filter>
1 您希望将被拒绝的消息发送到的消息通道。可选的。
2 底层 bean 定义的 ID。可选的。
3 此端点的接收消息通道。可选的。
4 您希望将接受的消息发送到的消息通道。可选的。
5 设置架构的位置以验证消息的有效负载。内部使用org.springframework.core.io.Resource接口。您可以设置此属性或xml-validator属性,但不能同时设置。可选的。
6 设置架构类型。可以是xml-schemarelax-ng。可选的。如果未设置,则默认为xml-schema,内部转换为org.springframework.xml.validation.XmlValidatorFactory#SCHEMA_W3C_XML
7 If trueMessageRejectedException如果对提供的 Message 的有效负载的验证失败,则抛出 a。false如果未设置,则默认为。可选的。
8 引用自定义org.springframework.integration.xml.XmlPayloadConverter策略。可选的。
9 引用自定义sorg.springframework.xml.validation.XmlValidator策略。您可以设置此属性或schema-location属性,但不能同时设置。可选的。
10 与 XPath 过滤器一起使用的轮询器。可选的。

1. see XML Configuration