Transforming XML Messages with XPath

说到消息转换,XPath 是一种转换具有 XML 有效负载的消息的好方法。可以通过使用 <xpath-transformer/> 元素定义 XPath 转换器来实现。

When it comes to message transformation, XPath is a great way to transform messages that have XML payloads. You can do so by defining XPath transformers with the <xpath-transformer/> element.

Simple XPath Transformation

考虑以下转换器配置:

Consider following transformer configuration:

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

还需要考虑以下 Message

Also consider the following Message:

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

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

After sending this message to the 'inputChannel', the XPath transformer configured earlier transforms this XML Message to a simple Message with a payload of 'John Doe', all based on the simple XPath Expression specified in the xpath-expression attribute.

XPath 还允许你对提取的元素执行简单转换以获得所需类型。在 javax.xml.xpath.XPathConstants 中定义了有效的返回类型,且遵循了 javax.xml.xpath.XPath 接口指定的转换规则。

XPath also lets you perform simple conversion of an extracted element to a desired type. Valid return types are defined in javax.xml.xpath.XPathConstants and follow the conversion rules specified by the javax.xml.xpath.XPath interface.

XPathConstants 类定义了以下常量:BOOLEANDOM_OBJECT_MODELNODENODESETNUMBERSTRING

The following constants are defined by the XPathConstants class: BOOLEAN, DOM_OBJECT_MODEL, NODE, NODESET, NUMBER, and STRING.

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

You can configure the desired type by using the evaluation-type attribute of the <xpath-transformer/> element, as the following example shows (twice):

<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"/>

Node Mappers

如果你需要为 XPath 表达式提取的节点提供自定义映射,则可以提供 org.springframework.xml.xpath.NodeMapper(一个由 XPathOperations 实现用于针对每个节点映射 Node 对象的接口)实现的引用。若要提供对 NodeMapper 的引用,你可以使用 node-mapper 属性,如以下示例所示:

If you need to provide custom mapping for the node extracted by the XPath expression, you can provide a reference to the implementation of the org.springframework.xml.xpath.NodeMapper (an interface used by XPathOperations implementations for mapping Node objects on a per-node basis). To provide a reference to a NodeMapper, you can use the node-mapper attribute, as the following example shows:

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

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

The following example shows a NodeMapper implementation that works with the preceding example:

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

XML Payload Converter

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

You can also use an implementation of the org.springframework.integration.xml.XmlPayloadConverter to provide more granular transformation. The following example shows how to define one:

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

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

The following example shows an XmlPayloadConverter implementation that works with the preceding example:

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 可能比在此处提供对该策略的自定义实现的引用更好的选择。

If you do not provide this reference, the DefaultXmlPayloadConverter is used. It should suffice in most cases, because it can convert from Node, Document, Source, File, String, InputStream, and byte[] payloads. If you need to extend beyond the capabilities of that default implementation, an upstream Transformer is probably a better option than providing a reference to a custom implementation of this strategy here.