# XML 支持-处理 XML 有效负载
# XML 支持-处理 XML 有效负载
Spring Integration 的 XML 支持扩展了 Spring Integration 与以下组件的核心:
你需要在项目中包含此依赖项:
Maven
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-xml</artifactId>
<version>5.5.9</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-xml:5.5.9"
这些组件使得在 Spring 集成中处理 XML 消息变得更加简单。消息传递组件使用以一系列格式表示的 XML,包括java.lang.String
、org.w3c.dom.Document
和javax.xml.transform.Source
的实例。但是,如果需要 DOM 表示(例如,为了计算 XPath 表达式),则将String
有效负载转换为所需的类型,然后将其转换回String
。需要DocumentBuilder
实例的组件如果不提供名称空间感知实例,则创建该实例。当需要对文档创建进行更大的控制时,可以提供DocumentBuilder
的适当配置实例。
# 名称空间支持
Spring 集成 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 集成 XML 模块中的许多组件都使用 XPath 表达式。这些组件中的每一个都引用了已定义为顶级元素的 XPath 表达式,或者使用了嵌套的<xpath-expression/>
元素。
所有形式的 XPath 表达式都会创建一个XPathExpression
,该表达式使用 Spring org.springframework.xml.xpath.XPathExpressionFactory
。在创建 XPath 表达式时,将使用 Classpath 上可用的最佳 XPath 实现(JAXP1.3+ 或 JAXen,其中首选 JAXP)。
在内部, Spring 集成使用了 Spring Web 服务项目(https://www.spring.io/spring-ws (opens new window))提供的 XPath 功能。 具体地说,我们使用 Spring Web 服务 XML 模块( Spring-xml-x.x.x.jar)。 有关更深入的理解,请参见https://docs.spring.io/spring-ws/docs/current/reference/#xpath (opens new window)上的相应文档。 |
---|
下面是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 名称空间前面提到过的选项:
<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](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]很好地总结了这一点:
在 XPath1.0 中,所有无前缀的名称都是不合格的。 不需要 XPath 表达式中使用的前缀与被查询的文档中使用的前缀相同。 只有名称空间 URI 需要匹配,而不是前缀。
# 转换 XML 有效负载
本节介绍了如何转换 XML 有效负载。
# 将变压器配置为 bean
本节将解释以下转换器的工作方式,以及如何将它们配置为 bean:
所有的 XML 转换器都扩展了[AbstractTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/Transformer/AbstractTransformer.html)或[AbstractPayloadTransformer
(https://DOCS. Spring.io/ Spring-integration/api/org/org/integration/AbstractTransformer/AbstractTransformer/AbstractTransformer/AbstractTransformer/AbstractTransformer.html),并因此实现了[](https:////DOCS. Spring-integration/在 Spring 集成中将 XML 转换器配置为 bean 时,通常需要结合[Transformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/Transforminghandler/MessageTransforminghandler.html)配置<gtr="116"/>。这使得变压器可以用作端点。最后,我们讨论了名称空间支持,它允许将转换器配置为 XML 中的元素。
# 解组变压器
[UnmarshallingTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/transformer/unmarshallingtransformer.html)允许使用Spring OXM (opens new window)Unmarshaller
的实现来解组 XMLSource
。 Spring 的对象/XML 映射支持提供了几种实现,通过使用JAXB (opens new window)、Castor (opens new window)、JiBX (opens new window)和其他方式支持编组和解组。解组器需要Source
的实例。如果消息有效负载不是Source
的实例,则仍将尝试转换。目前,String
、File
、byte[]
和org.w3c.dom.Document
都支持有效载荷。要创建到Source
的自定义转换,可以注入一个[SourceFactory
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/sourcefactory.html)的实现。
如果你没有显式地设置SourceFactory ,则UnmarshallingTransformer 上的属性默认设置为[DomSourceFactory ](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/domsourceFactory.html)。 |
---|
从版本 5.0 开始,UnmarshallingTransformer
还支持将org.springframework.ws.mime.MimeMessage
作为传入负载。当我们通过 SOAP 接收带有 MTOM 附件的 RAWWebServiceMessage
时,这可能是有用的。有关更多信息,请参见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
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/Transformer/MarshallingTransformer.html)允许通过使用 Spring OXMMarshaller
将对象图转换为 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
[XsltPayloadTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/transformer/xsltpayloadTransformer.html)通过使用可扩展样式表语言转换 (opens new window)转换 XML 有效负载。Transformer 的构造函数需要传入Resource (opens new window)或Templates (opens new window)的实例。传入Templates
实例可以更好地配置用于创建模板实例的TransformerFactory
实例。
与[UnmarshallingTransformer
](#xml-unmarshalling-transformer)一样,XsltPayloadTransformer
针对Source
的实例执行实际的 XSLT 转换。因此,如果消息有效负载不是Source
的实例,则仍然尝试进行转换。String
和Document
有效负载是直接支持的。
要创建到Source
的自定义转换,你可以注入一个[SourceFactory
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/sourcefactory.html)的实现。
如果SourceFactory 未显式设置,则XsltPayloadTransformer 上的属性默认设置为[DomSourceFactory ](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/domsourceFactory.html)。 |
---|
默认情况下,XsltPayloadTransformer
创建带有[Result
](https://DOCS.oracle.com/javase/6/DOCS/api/javax/xml/transform/result.html)有效负载的消息,类似于XmlPayloadMarshallingTransformer
。你可以通过提供[ResultFactory
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/result/resultfactory.html)或[ResultTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/transformer/resultformer.html)来对此进行定制。
下面的示例配置 Bean 作为 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 Integration3.0 开始,你可以通过使用构造函数参数来指定 Transformer Factory 类名。在使用名称空间时,可以使用transformer-factory-class
属性来实现此目的。
# 使用ResultTransformer
实现
MarshallingTransformer
和XsltPayloadTransformer
都允许你指定一个[ResultTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/Transformer/resultTransformer.html)。因此,如果编组或 XSLT 转换返回[Result
](https://DOCS.oracle.com/javase/6/DOCS/api/javax/xml/transform/result.html),则你还可以选择使用ResultTransformer
将Result
转换为另一种格式。 Spring 集成提供了两个具体的ResultTransformer
实现:
[
ResultToDocumentTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/Transformer/ResultToDocumentTransformer.html)[
ResultToStringTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/Transformer/resultoStringTransformer.html)
默认情况下,MarshallingTransformer
总是返回一个[Result
](https://DOCS.oracle.com/javase/6/DOCS/api/javax/xml/transform/result.html)。通过指定ResultTransformer
,你可以自定义返回的有效负载的类型。
对于XsltPayloadTransformer
,行为稍微复杂一些。默认情况下,如果输入有效负载是String
或[Document
](https://DOCS.oracle.com/javase/6/DOCS/api/org/w3c/dom/document.html)的实例,则resultTransformer
属性将被忽略。
但是,如果输入有效负载是[Source
](https://DOCS.oracle.com/javase/6/DOCS/api/javax/xml/transform/source.html)或任何其他类型,则应用resultTransformer
属性。此外,你可以将alwaysUseResultFactory
属性设置为true
,这也会导致使用指定的resultTransformer
。
有关更多信息和示例,请参见名称空间配置和结果转换器。
# XML Transformers 的命名空间支持
Spring Integration XML 命名空间提供了对所有 XML 转换器的命名空间支持,其模板为显示在前面。对 Transformers 的命名空间支持根据所提供的输入通道的类型创建EventDrivenConsumer
或PollingConsumer
的实例。名称空间支持旨在通过允许创建使用一个元素的端点和转换器来减少 XML 配置的数量。
# 使用UnmarshallingTransformer
UnmarshallingTransformer
的命名空间支持如下所示。由于名称空间创建的是一个端点实例,而不是一个转换器,因此你可以在元素中嵌入一个 poller 来控制输入通道的轮询。下面的示例展示了如何做到这一点:
<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"/>
如果提供的结果类型不够,则可以提供对ResultFactory
的自定义实现的引用,作为使用result-type
属性设置result-type
属性的替代方法。result-type
和result-factory
属性是互斥的。
在内部,StringResult 和DomResult 结果类型由ResultFactory 实现表示:[StringResultFactory ](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/result/stringresultfactory.html)和[DomResultFactory (https://DOCS. Spring.io/ Spring-integration/api/api/integration/xml/result/resultfactory.html)。 |
---|
# 使用XsltPayloadTransformer
对XsltPayloadTransformer
的命名空间支持允许你传入Resource
(以便创建[Templates
](https://DOCS.oracle.com/javase/6/DOCS/api/javax/xml/transform/templates.html)实例)或传入预先创建的Templates
实例作为参考。与编组转换器一样,你可以通过指定result-factory
或result-type
属性来控制结果输出的类型。当需要在发送之前转换结果时,可以使用result-transformer
属性来引用ResultTransformer
的实现。
如果指定result-factory 或result-type 属性,则底层[alwaysUseResultFactory ](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/Transformer/xsltpayloadformer.html)上的true 属性将被[<<XsltPayloadTransformerParser ](https://DOCS. Spring.api/api/api/api/api/api/api63/apylotframFramework/xtframework/xparser.html)设置 |
---|
下面的示例配置了两个 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 集成提供了两种方便的方式来实现这一点,如下例所示:
<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 Integration3.0 开始,你现在可以通过设置transformer-factory-class
属性来指定 Transformer Factory 类名称。
# 名称空间配置和结果转换器
我们在[使用ResultTransformer
实现](#xml-using-result-transformers)中介绍了使用结果转换器的情况。本节中的示例使用 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
,则作为一个后备选项,我们尝试通过使用默认的[Source
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/sourcefactory.html)来创建Source
。由于我们没有使用source-factory
属性显式地指定SourceFactory
,因此使用了默认的[DomSourceFactory
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/source/domsourcefactory.html)。如果成功,将执行 XSLT 转换,就好像负载类型Source
一样,如前面几段所述。
DomSourceFactory 支持从Document 、File 或String 有效负载创建DOMSource 。 |
---|
下一个 Transformer 声明添加了一个result-type
属性,该属性使用StringResult
作为其值。result-type
在内部由StringResultFactory
表示。因此,你还可以通过使用result-factory
属性添加对StringResultFactory
的引用,该属性本来是相同的。下面的示例展示了 Transformer 声明:
<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
](https://DOCS.oracle.com/javase/6/DOCS/api/org/w3c/dom/document.html)。
# XsltPayloadTransformer
和<xsl:output method="text"/>
<xsl:output method="text"/>
告诉 XSLT 模板仅从输入源生成文本内容。在这种特殊情况下,我们没有理由使用DomResult
。因此,[XsltPayloadTransformer
](https://DOCS. Spring.io/ Spring-integration/api/org/springframework/integration/xml/transformer/xsltpayloadTransformer.html)默认为StringResult
如果[输出属性](https://docs.oracle.com/javase/7/docs/api/javax/xml/transform/Transformer.html#getOutputProperties())调用底层method
的javax.xml.transform.Transformer
返回text
。这种强制执行独立于入站有效负载类型。只有为<int-xml:xslt-transformer>
组件设置 ifresult-type
属性或result-factory
属性时,此行为才可用。
# 使用 XPath 转换 XML 消息
当涉及到消息转换时,XPath 是转换具有 XML 有效负载的消息的一种很好的方法。你可以通过使用<xpath-transformer/>
元素定义 XPath Transformers 来实现此目的。
# 简单的 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 Transformer 将此 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 Splitter 名称空间支持允许你创建带有输入通道和输出通道的消息端点,如下例所示:
<!-- 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 开始,当请求payload
类型不是org.w3c.dom.Node
时,outputProperties
实例的OutputKeys.OMIT_XML_DECLARATION
属性(例如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
时,首先对所有条目进行转换,然后将分割的节点开始发送到输出通道。(你可以将其视为“transform,send,transform,send,send”与“transform,transform,send,send”的区别。)有关更多信息,请参见Splitter。
# 使用 XPath 路由 XML 消息
Spring 与基于 SPEL 的路由器类似,集成提供了对基于 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
求值类型。
XPath1.0 指定了 4 种数据类型: *node-sets *strings *number boolean当使用可选路径 时,返回值由 string() 函数求值,正如 XPath 规范中所定义的。这意味着,如果表达式选择了多个节点,它将返回第一个节点的字符串值。 有关更多信息,请参见: 规范:XMLPath 语言 1.0 版本 (opens new window) XPath 规范-string()函数 (opens new window) |
---|
例如,如果我们想基于根节点的名称进行路由,我们可以使用以下配置:
<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
。在大多数情况下,它应该足够了,因为它可以从节点、文档、源、文件和字符串类型的有效负载转换。如果你需要扩展到该默认实现的能力之外,那么在大多数情况下,上游转换器通常是更好的选择,而不是在这里提供对此策略的自定义实现的引用。
# XPath Header Enricher
XPath Header Enricher 定义了 Header Enricher 消息转换器,该消息转换器根据消息有效负载计算 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 | 指定是否覆盖现有标头值的默认布尔值。 这仅对不提供自己的“覆盖”属性的子元素有效, 如果不设置“默认-覆盖”属性,指定的标头值不会覆盖任何具有相同标头名的现有标头值。 可选。 |
---|---|
2 | ID 为底层的 Bean 定义。 可选的。 |
3 | 这个端点的接收消息通道。 可选的。 |
4 | 丰富的消息被发送到的通道。 可选。 |
5 | 指定是否应跳过空值,例如可能从表达式求值返回的空值。 默认值是 true 。如果空值应触发删除相应的标头,请将其设置为 false 。可选。 |
6 | 与标题 Enricher 一起使用的 Poller。 可选的。 |
7 | 要丰富的标题的名称。 强制。 |
8 | 如果你没有设置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 )。中讨论的相同的积分 ConversionService 用于转换,因此通过向服务中添加一个自定义转换器可以支持到自定义类型的转换。可选。 |
10 | 布尔值,用于指示如果输入Message 中已经存在,则此头标值是否应覆盖相同名称的现有头标值。 |
11 | XPath 表达式为String 。必须设置这个属性或 xpath-expression-ref ,但不能同时设置这两个属性。 |
12 | XPath 表达式引用. 必须设置这个属性或 xpath-expression ,但不能同时设置这两个属性。 |
# 使用 XPath 过滤器
这个组件定义了一个基于 XPath 的消息过滤器。在内部,这个组件使用MessageFilter
来包装AbstractXPathMessageSelector
的实例。
有关更多详细信息,请参见Filter。 |
---|
要使用 XPath 过滤器,你至少必须通过声明xpath-expression
元素或在xpath-expression-ref
属性中引用一个 XPath 表达式来提供一个 XPath 表达式。
如果提供的 XPath 表达式计算为boolean
值,则不需要进一步的配置参数。但是,如果 XPath 表达式的求值为String
,则应该设置match-value
属性,并与求值结果进行匹配。
match-type
有三种选择:
exact
:在java.lang.String
上对应于equals
。底层实现使用StringValueTestXPathMessageSelector
case-insensitive
:在java.lang.String
上对应于equals-ignore-case
。底层实现使用StringValueTestXPathMessageSelector
regex
:匹配操作 1java.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 | ID 为底层的 Bean 定义。 可选的。 |
3 | 这个端点的接收消息通道。 可选。 |
4 | 要在 XPath 求值结果和match-value 之间应用匹配的类型。默认值是 exact 。可选的。 |
5 | 要与 XPath 求值结果匹配的字符串值。 如果不设置此属性,则 XPath 求值必须产生一个布尔结果。 可选。 |
6 | 将与筛选条件匹配的消息发送到的通道。 可选。 |
7 | 默认情况下,此属性被设置为false ,并且被拒绝的消息(与筛选条件不匹配的消息)将被静默删除。但是,如果设置为 true ,则消息拒绝将导致一个错误条件,并且异常将向上传播到调用者。可选。 |
8 | 引用 XPath 表达式实例进行求值。 |
9 | 此子元素设置要求值的 XPath 表达式。 如果不包含此元素,则必须设置 xpath-expression-ref 属性。此外,你只能包含一个 xpath-expression 元素。 |
10 | 与 XPath 过滤器一起使用的 Poller。 可选的。 |
# #XPath spel 函数
Spring 集成,自版本 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>
#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 添加到 Classpath。你不需要从 Spring 集成 XML 命名空间中声明任何组件。 |
---|
有关更多信息,请参见“`Spring Expression Language (SpEL)。
# XML 验证过滤器
XML 验证过滤器允许你根据提供的模式实例验证传入消息。支持以下模式类型:
xml-schema(https://www.w3.org/2001/XMLSchema (opens new window))
relax-ng(https://relaxng.org (opens new window))
验证失败的消息可以被静默删除,也可以转发到可定义的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 | ID 为底层的 Bean 定义。 可选的。 |
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 过滤器一起使用的 Poller。 可选的。 |