Namespace Support

All components within the Spring Integration XML module provide namespace support. In order to enable namespace support, you need to import the schema for the Spring Integration XML Module. The following example shows a typical setup:

<?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 Expressions

Many of the components within the Spring Integration XML module work with XPath Expressions. Each of those components either references an XPath Expression that has been defined as a top-level element or uses a nested <xpath-expression/> element.

All forms of XPath expressions result in the creation of an XPathExpression that uses the Spring org.springframework.xml.xpath.XPathExpressionFactory. When XPath expressions are created, the best XPath implementation that is available on the classpath is used (either JAXP 1.3+ or Jaxen, with JAXP being preferred).

Internally, Spring Integration uses the XPath functionality provided by the Spring Web Services project (www.spring.io/spring-ws). Specifically, we use the Spring Web Services XML module (spring-xml-x.x.x.jar). For a deeper understanding, see the respective documentation at docs.spring.io/spring-ws/docs/current/reference/#xpath.

Here is an overview of all available configuration parameters of the xpath-expression element: The following listing shows the available attributes for the xpath-expression element:

<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 Defines an XPath expression. Required.
2 The identifier of the underlying bean definition. It is an instance of org.springframework.xml.xpath.XPathExpression. Optional.
3 Reference to a map that contains namespaces. The key of the map defines the namespace prefix, and the value of the map sets the namespace URI. It is not valid to specify both this attribute and the map element or the ns-prefix and ns-uri attributes. Optional.
4 Lets you set the namespace prefix directly as an attribute on the XPath expression element. If you set ns-prefix, you must also set the ns-uri attribute. Optional.
5 Lets you directly set the namespace URI as an attribute on the XPath expression element. If you set ns-uri, you must also set the ns-prefix attribute. Optional.
6 Defines a map that contains namespaces. Only one map child element is allowed. The key of the map defines the namespace prefix, and the value of the map sets the namespace URI. It is not valid to specify both this element and the map attribute or set the ns-prefix and ns-uri attributes. Optional.

Providing Namespaces (Optional) to XPath Expressions

For the XPath Expression Element, you can provide namespace information as configuration parameters. You can define namespaces by using one of the following choices:

  • Reference a map by using the namespace-map attribute

  • Provide a map of namespaces by using the map sub-element

  • Specify the ns-prefix and ns-uri attributes

All three options are mutually exclusive. Only one option can be set.

The following example shows several different ways to use XPath expressions, including the options for setting the XML namespaces 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>

Using XPath Expressions with Default Namespaces

When working with default namespaces, you may run into situations that behave differently than you might expect. Assume we have the following XML document (which represents an order of two books):

<?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>

This document does not declare a namespace. Therefore, applying the following XPath Expression works as expected:

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

You might expect that the same expression also works for the following XML file:

<?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>

The preceding example looks exactly the same as the previous example but declares a default namespace.

However, the previous XPath expression (/order/orderItem) fails in this case.

In order to solve this issue, you must provide a namespace prefix and a namespace URI either by setting the ns-prefix and ns-uri attributes or by setting the namespace-map attribute. The namespace URI must match the namespace declared in your XML document. In the preceding example, that is www.example.org/orders.

You can, however, arbitrarily choose the namespace prefix. In fact, providing an empty string actually works. (However, null is not allowed.) In the case of a namespace prefix consisting of an empty string, your Xpath expression must use a colon (":") to indicate the default namespace. If you leave off the colon, the XPath expression does not match. The following XPath Expression matches against the XML document in the preceding example:

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

You can also provide any other arbitrarily chosen namespace prefix. The following XPath expression (which use the myorder namespace prefix) also matches:

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

The namespace URI is the really important piece of information, not the prefix. The Jaxen summarizes the point very well:

In XPath 1.0, all unprefixed names are unqualified. There is no requirement that the prefixes used in the XPath expression are the same as the prefixes used in the document being queried. Only the namespace URIs need to match, not the prefixes.