XML 支持 - 处理 XML 有效负载
XML 支持 - 处理 XML 响应
Spring Integration 的 XML 支持通过以下组件扩展了 Spring Integration 的核心功能:
您需要将以下依赖项包含到您的项目中:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-xml</artifactId>
<version>6.1.9</version>
</dependency>
compile "org.springframework.integration:spring-integration-xml:6.1.9"
这些组件使在 Spring Integration 中处理 XML 消息变得更加简单。
消息组件支持与各种格式表示的 XML,包括 java.lang.String、org.w3c.dom.Document 和 javax.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 表达式都会创建一个使用 Spring org.springframework.xml.xpath.XPathExpressionFactory 的XPathExpression。
创建 XPath 表达式时,将使用类路径上可用的最佳 XPath 实现(JAXP 1.3+ 或 Jaxen,优先选择 JAXP)。
| 内部地,Spring Integration 使用 Spring Web Services 项目提供的 XPath 功能 (https://www.spring.io/spring-ws)。 具体来说,我们使用的是 Spring Web Services XML 模块 (spring-xml-x.x.x.jar)。 如需更深入的理解,请参阅 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 | 对包含命名空间的映射的引用。
映射的键定义命名空间前缀,映射的值设置命名空间 URI。
同时指定此属性与 map 元素或 ns-prefix 和 ns-uri 属性是无效的。
可选。 |
| 4 | 允许您直接将命名空间前缀作为 XPath 表达式元素的属性进行设置。
如果您设置了 ns-prefix,还必须同时设置 ns-uri 属性。
可选。 |
| 5 | 允许您直接将命名空间 URI 作为 XPath 表达式元素的属性进行设置。
如果您设置了 ns-uri,则还必须设置 ns-prefix 属性。
可选。 |
| 6 | 定义一个包含命名空间的映射。
只允许有一个 map 子元素。
映射的键定义命名空间前缀,映射的值设置命名空间 URI。
同时指定此元素和 map 属性,或同时设置 ns-prefix 和 ns-uri 属性是无效的。
可选。 |
为 XPath 表达式提供命名空间(可选)
对于 XPath 表达式元素,您可以将命名空间信息作为配置参数提供。 您可以通过以下任一方式定义命名空间:
-
通过
namespace-map属性引用一个映射 -
使用
map子元素提供命名空间映射 -
指定
ns-prefix和ns-uri属性
这三个选项是互斥的。 只能设置其中一个选项。
以下示例展示了使用 XPath 表达式的几种不同方式,包括之前提到的设置 XML 命名空间的选项:mentioned earlier:
<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-prefix 和 ns-uri 属性或设置 namespace-map 属性来提供命名空间前缀和命名空间 URI。
命名空间 URI 必须与您 XML 文档中声明的命名空间相匹配。
在前面的示例中,该值为 http://www.example.org/orders。
不过,您可以任意选择命名空间前缀。 事实上,提供空字符串也是有效的。 (但 null 是不允许的。) 对于由空字符串组成的命名空间前缀,您的 XPath 表达式必须使用冒号(":")来表示默认命名空间。 如果省略冒号,XPath 表达式将无法匹配。 以下 XPath 表达式可与 preceding example 中的 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 是真正重要的信息,而非前缀。 Jaxen 对此总结得非常到位:
在 XPath 1.0 中,所有无前缀的名称都是非限定名。 XPath 表达式中使用的命名空间前缀不必与要查询的文档中使用的命名空间前缀相同。 只需要命名空间 URI 匹配,而不需要前缀匹配。
转换 XML 负载
本节介绍如何转换 XML 负载
配置转换器为 Bean
本节将解释以下转换器的运作方式,并说明如何将其配置为 Bean:
所有 XML 转换器都扩展自 AbstractTransformer 或 AbstractPayloadTransformer,因此实现了 Transformer。
在 Spring Integration 中将 XML 转换器配置为 Bean 时,通常会将 Transformer 与 MessageTransformingHandler 一起配置。
这使得转换器可以作为端点使用。
最后,我们讨论命名空间支持,它允许将转换器配置为 XML 中的元素。
反序列化转换器
一个 UnmarshallingTransformer 允许使用 Spring OXM Unmarshaller 的实现来反序列化 XML Source。
Spring 的对象/XML 映射支持提供了多种实现,这些实现支持通过 JAXB、Castor、JiBX 等进行编组和解组。
反序列化器需要一个 Source 的实例。
如果消息负载不是 Source 的实例,仍会尝试进行转换。
目前支持 String、File、byte[] 和 org.w3c.dom.Document 类型的负载。
若要创建自定义转换以转换为 Source,可以注入 SourceFactory 的一个实现。
如果您没有显式设置 SourceFactory,则 UnmarshallingTransformer 上的属性默认会被设置为 DomSourceFactory。 |
从 5.0 版本开始,UnmarshallingTransformer 也支持将 org.springframework.ws.mime.MimeMessage 作为传入的有效负载。
当我们在 SOAP 中收到带有 MTOM 附件的原始 WebServiceMessage 时,这可能非常有用。
有关更多信息,请参阅 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
The MarshallingTransformer 允许通过使用 Spring OXM Marshaller 将对象图转换为 XML。
默认情况下,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
The XsltPayloadTransformer通过使用可扩展样式表语言转换(XSLT)来转换XML负载。
transformer的构造函数需要传入一个Resource或Templates实例。
传入Templates实例允许对用于创建模板实例的TransformerFactory进行更详细的配置。
与 UnmarshallingTransformer 类似,XsltPayloadTransformer 会对 Source 的实例执行实际的 XSLT 转换。
因此,如果消息负载不是 Source 的实例,仍会尝试进行转换。
String 和 Document 类型的负载可直接支持。
要创建转换为 Source 的自定义转换器,您可以注入一个 SourceFactory 的实现。
如果未显式设置 SourceFactory,则 XsltPayloadTransformer 上的属性默认设置为 DomSourceFactory。 |
默认情况下,XsltPayloadTransformer会创建一个带有Result负载的消息,类似于XmlPayloadMarshallingTransformer。
您可以通过提供ResultFactory或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实现
Both the MarshallingTransformer and the XsltPayloadTransformer let you specify a ResultTransformer.
Thus, if the marshalling or XSLT transformation returns a Result, you have the option to also use a ResultTransformer to transform the Result into another format.
Spring Integration provides two concrete ResultTransformer implementations:
默认情况下,MarshallingTransformer 始终返回一个 Result。
通过指定 ResultTransformer,您可以自定义返回的负载类型。
对于 XsltPayloadTransformer,其行为稍微复杂一些。
默认情况下,如果输入负载是 String 的实例或 Document,则 resultTransformer 属性将被忽略。
然而,如果输入负载是 Source 或任何其他类型,则应用 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以及对marshaller的引用。
您可以使用可选的result-type属性来控制所创建结果的类型。
有效值为StringResult或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"/>
当提供的结果类型不足以满足需求时,您可以使用result-factory属性来引用自定义的ResultFactory实现,以此替代设置result-type属性。result-type和result-factory属性是互斥的。
在内部,StringResult和DomResult结果类型分别由ResultFactory实现表示:StringResultFactory和DomResultFactory。 |
使用XsltPayloadTransformer
命名空间支持允许您传入一个 XsltPayloadTransformer(用于创建 Templates 实例),或者传入一个预创建的 Templates 实例作为引用。
与编组转换器类似,您可以通过指定 result-factory 或 result-type 属性来控制结果输出的类型。
当需要在发送前转换结果时,您可以使用 result-transformer 属性来引用 ResultTransformer 的实现。
如果您指定了 result-factory 或 result-type 属性,则底层 XsltPayloadTransformer 的 alwaysUseResultFactory 属性将由 XsltPayloadTransformerParser 设置为 true。 |
以下示例配置了两个 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、*xxx 以及 xxx*yyy。
您还可以通过使用 <xslt-param/> 元素来配置单独的 XSLT 参数。
在该元素上,您可以设置 expression 属性或 value 属性。
expression 属性应为任何有效的 SpEL 表达式,其中 Message 是表达式求值上下文的根对象。
value 属性(与 Spring bean 中的任何 value 一样)允许您指定简单的标量值。
您还可以使用属性占位符(例如 ${some.value})。
因此,通过 expression 和 value 属性,您可以将 XSLT 参数映射到 Message 的任何可访问部分以及任何字面量值。
从 Spring Integration 3.0 开始,您可以通过设置 transformer-factory-class 属性来指定转换器工厂类名。
命名空间配置和结果转换器
我们介绍了在 使用ResultTransformer实现中如何使用结果转换器。
本节中的示例使用 XML 命名空间配置来说明几个特殊用例。
首先,我们定义 ResultTransformer,如下例所示:
<beans:bean id="resultToDoc" class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
此 ResultTransformer 接受 StringResult 或 DOMResult 作为输入,并将输入转换为 Document。
现在我们可以声明转换器,如下所示:
<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"/>
如果传入消息的负载类型为 Source,那么作为第一步,将通过使用 ResultFactory 来确定 Result。
由于我们未指定 ResultFactory,因此将使用默认的 DomResultFactory,这意味着转换结果将生成一个 DomResult。
然而,由于我们指定了 ResultTransformer,它被使用,生成的 Message 负载类型为 Document。
指定的 ResultTransformer 在 String 或 Document 负载下将被忽略。
如果传入消息的负载类型为 String,则经过 XSLT 转换后的负载为 String。
同样地,如果传入消息的负载类型为 Document,则经过 XSLT 转换后的负载为 Document。 |
如果消息负载不是 Source、String 或 Document,作为回退选项,我们将尝试使用默认的 SourceFactory 来创建 `Source`。
由于我们未通过 source-factory 属性显式指定 SourceFactory,因此使用了默认的 DomSourceFactory。
如果成功,XSLT 转换将如同消息负载为 Source 类型一样执行,如前文所述。
The DomSourceFactory supports the creation of a DOMSource from a Document, a File, or a String payload. |
下一个转换器声明添加了一个result-type属性,其值为StringResult。
result-type在内部由StringResultFactory表示。
因此,您也可以通过使用result-factory属性来添加对StringResultFactory的引用,结果是一样的。
以下示例展示了该转换器声明:
<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"
result-type="StringResult"/>
因为我们使用了 ResultFactory,所以 XsltPayloadTransformer 类的 alwaysUseResultFactory 属性被隐式设置为 true。
因此,引用的 ResultToDocumentTransformer 将被使用。
因此,如果您将类型为 String 的负载进行转换,生成的负载类型将为 Document。
XsltPayloadTransformer和<xsl:output method="text"/>
<xsl:output method="text"/> 告诉 XSLT 模板仅从输入源生成文本内容。
在这种情况下,我们没有理由使用 DomResult。
因此,如果底层 javax.xml.transform.Transformer 上名为 method 的 输出属性 返回 text,则 XsltPayloadTransformer 默认为 StringResult。
此强制转换独立于入站负载类型执行。
只有当为 <int-xml:xslt-transformer> 组件设置 result-type 属性或 result-factory 属性时,才可使用此行为。
使用 XPath 转换 XML 消息
当涉及消息转换时,XPath 是一种转换具有 XML 有效负载的消息的绝佳方式。
你可以通过定义 XPath 转换器来实现,使用 <xpath-transformer/> 元素。
简单 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 类定义:BOOLEAN, DOM_OBJECT_MODEL, NODE, NODESET, NUMBER 和 STRING。
您可以通过在<xpath-transformer/>元素上使用evaluation-type属性来配置所需的类型,如下面的示例所示(两次):
<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(一个接口,XPathOperations 的实现使用它按节点基础将 Node 对象进行映射)的引用。
要提供对 NodeMapper 的引用,您可以使用 node-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。
在大多数情况下这应该足够了,因为它可以转换来自Node、Document、Source、File、String、InputStream和byte[]的负载。
如果您需要超越该默认实现的能力,那么上游Transformer可能比在此处提供对此策略的自定义实现的引用是更好的选择。
拆分 XML 消息
XPathMessageSplitter 支持带有 String 或 Document 有效负载的消息。
拆分器使用提供的 XPath 表达式将有效负载拆分为多个节点。
默认情况下,这会导致每个 Node 实例成为新消息的有效负载。
当每条消息应为 Document 时,您可以设置 createDocuments 标志。
当传入 String 有效负载时,有效负载会被转换,然后拆分,再转换回多个 String 消息。
XPath 拆分器实现了 MessageHandler,因此应配合适当的端点进行配置(见下方示例后的命名空间支持示例,以获取更简单的配置替代方案)。
以下示例配置了一个使用 XPathMessageSplitter 的 Bean:
<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 会在请求 payload 不是类型 org.w3c.dom.Node 时,为 javax.xml.transform.Transformer 实例暴露 outputProperties(例如 OutputKeys.OMIT_XML_DECLARATION)属性。
以下示例定义了一个属性并使用它与 output-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 将 iterator 选项作为 boolean 标志(默认为 true)进行暴露。
这允许在下游流程中“流式传输”拆分节点。
当 iterator 模式设置为 true 时,每个节点在迭代过程中都会被转换。
当 false 时,所有条目会先被转换,然后拆分节点才开始发送到输出通道。
(你可以将这种差异理解为“转换、发送、转换、发送”与“转换、转换、发送、发送”之间的区别。)
有关更多信息,请参阅 Splitter。
使用 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>。
通常,此类列表仅包含一个通道名称。
然而,基于 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 表达式产生两个值(responderA 和 responderB),但您不希望将响应者名称与通道名称耦合,您可以提供额外的映射配置,如下所示:
<!-- 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。
但是,如果您将其设置为 TRUE,则将使用 String 评估类型。
|
XPath 1.0 指定了 4 种数据类型:
当 XPath Router 使用可选的 更多信息,请参见: |
例如,如果我们想根据根节点的名称进行路由,可以使用以下配置:
<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 | 指定是否覆盖现有头部值的默认布尔值。 它仅对未提供自身"overwrite"属性的子元素生效。 如果您未设置"default-overwrite"属性,则指定的头部值不会覆盖任何具有相同头部名称的现有值。 可选。 |
| 2 | 底层 bean 定义的 ID。 可选。 |
| 3 | 此端点的接收消息通道。 可选。 |
| 4 | 发送增强消息的通道。 可选。 |
| 5 | 指定是否应跳过空值(例如从表达式评估返回的空值)。
默认值为 true。
如果空值应触发移除相应的标题,请将其设置为 false。
可选。 |
| 6 | 用于与头部增强器配合使用的轮询器。 可选。 |
| 7 | 要丰富化的表头名称。 必填项。 |
| 8 | XPath 评估期望的结果类型。
如果您未设置 header-type 属性,则这是头值的类型。
允许的值包括:BOOLEAN_RESULT、STRING_RESULT、NUMBER_RESULT、NODE_RESULT 和 NODE_LIST_RESULT。
若未设置,内部默认值为 XPathEvaluationType.STRING_RESULT。
可选。 |
| 9 | 头部值类型的完全限定类名。
XPath 评估的结果将通过 ConversionService 转换为该类型。
例如,这允许将 NUMBER_RESULT(一个 double)转换为 Integer。
该类型可以声明为基本类型(例如 int),但结果始终是等效的包装类(例如 Integer)。
此处使用的集成机制与负载类型转换中讨论的相同,因此通过向服务添加自定义转换器,支持转换为自定义类型。
可选。 |
| 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 表达式求值为 String,您应该设置 match-value 属性,以便将求值结果与该属性进行匹配。
match-type 有三个选项:
-
exact: 对应equals上的java.lang.String。 底层实现使用了StringValueTestXPathMessageSelector -
case-insensitive: 对应equals-ignore-case上的java.lang.String。 底层实现使用了StringValueTestXPathMessageSelector -
regex: 匹配一个java.lang.String操作。 底层实现使用了RegexTestXPathMessageSelector
当提供 'match-type' 值为 'regex' 时,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 | Type of match to apply between the XPath evaluation result and the match-value.
The default is exact.
Optional. |
| 5 | 要与 XPath 评估结果匹配的字符串值。 如果您未设置此属性,则 XPath 评估必须产生布尔类型结果。 可选。 |
| 6 | 匹配筛选条件的消息将被分发到的通道。 可选。 |
| 7 | 默认情况下,此属性设置为 false,未匹配筛选条件的消息会被静默丢弃。
然而,如果设置为 true,消息拒绝将导致错误条件,并向调用方传播异常。
可选。 |
| 8 | 对要评估的 XPath 表达式实例的引用。 |
| 9 | 此子元素用于设置要评估的 XPath 表达式。
如果您未包含此元素,则必须设置 xpath-expression-ref 属性。
此外,您只能包含一个 xpath-expression 元素。 |
| 10 | 一个用于 XPath 过滤器的轮询器。 可选。 |
#xpath SpEL 函数
Spring Integration 自 3.0 版本起,提供了内置的 #xpath SpEL 函数,该函数会调用 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>
The #xpath() 还支持第三个可选参数,用于转换 XPath 评估的结果。
它可以是字符串常量 (string, boolean, number, node, node_list 和 document_list) 之一,也可以是 org.springframework.xml.xpath.NodeMapper 的实例。
默认情况下,#xpath SpEL 函数返回 XPath 评估的 String 表示形式。
要启用 #xpath SpEL 函数,您可以将 spring-integration-xml.jar 添加到类路径中。
您无需从 Spring Integration XML 命名空间声明任何组件。 |
更多信息,请参见"`Spring 表达式语言 (SpEL)"。
XML 验证过滤器
XML 验证过滤器允许您根据提供的模式实例对传入的消息进行验证。 支持以下类型的模式:
-
xml-schema (https://www.w3.org/2001/XMLSchema)
-
relax-ng (https://relaxng.org)
无法通过验证的消息要么被静默丢弃,要么转发到可定义的 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-schema 或 relax-ng。
可选参数。
如果未设置,则默认为 xml-schema,其内部会转换为 org.springframework.xml.validation.XmlValidatorFactory#SCHEMA_W3C_XML。 |
| 7 | 如果为true,当提供的消息有效载荷验证失败时将抛出MessageRejectedException。
若未设置,默认为false。
可选。 |
| 8 | 对自定义 org.springframework.integration.xml.XmlPayloadConverter 策略的引用。
可选。 |
| 9 | 对自定义 sorg.springframework.xml.validation.XmlValidator 策略的引用。
您可以设置此属性或 schema-location 属性,但不能同时设置两者。
可选。 |
| 10 | 一个用于 XPath 过滤器的轮询器。 可选。 |