| ## XML JSon DataFormat |
| |
| *Available as of Camel version 2.10* |
| |
| Camel already supports a number of data formats to perform XML and |
| JSON-related conversions, but all of them require a POJO either as an |
| input (for marshalling) or produce a POJO as output (for unmarshalling). |
| This data format provides the capability to convert from XML to JSON and |
| vice-versa directly, without stepping through intermediate POJOs. |
| |
| This data format leverages the |
| http://json-lib.sourceforge.net/[Json-lib] library to achieve direct |
| conversion. In this context, XML is considered the high-level format, |
| while JSON is the low-level format. Hence, the marshal/unmarshal |
| semantics are assigned as follows: |
| |
| * marshalling => converting from XML to JSON |
| * unmarshalling => converting from JSON to XML. |
| |
| ### Options |
| |
| // dataformat options: START |
| The XML JSon dataformat supports 13 options which are listed below. |
| |
| |
| |
| [width="100%",cols="2s,1m,1m,6",options="header"] |
| |======================================================================= |
| | Name | Default | Java Type | Description |
| | encoding | | String | Sets the encoding. Used for unmarshalling (JSON to XML conversion). |
| | elementName | | String | Specifies the name of the XML elements representing each array element. Used for unmarshalling (JSON to XML conversion). |
| | arrayName | | String | Specifies the name of the top-level XML element. Used for unmarshalling (JSON to XML conversion). For example when converting 1 2 3 it will be output by default as 123. By setting this option or rootName you can alter the name of element 'a'. |
| | forceTopLevelObject | false | Boolean | Determines whether the resulting JSON will start off with a top-most element whose name matches the XML root element. Used for marshalling (XML to JSon conversion). If disabled XML string 12 turns into 'x: '1' 'y': '2' . Otherwise it turns into 'a': 'x: '1' 'y': '2' . |
| | namespaceLenient | false | Boolean | Flag to be tolerant to incomplete namespace prefixes. Used for unmarshalling (JSON to XML conversion). In most cases json-lib automatically changes this flag at runtime to match the processing. |
| | rootName | | String | Specifies the name of the top-level element. Used for unmarshalling (JSON to XML conversion). If not set json-lib will use arrayName or objectName (default value: 'o' at the current time it is not configurable in this data format). If set to 'root' the JSON string 'x': 'value1' 'y' : 'value2' would turn into value1value2 otherwise the 'root' element would be named 'o'. |
| | skipWhitespace | false | Boolean | Determines whether white spaces between XML elements will be regarded as text values or disregarded. Used for marshalling (XML to JSon conversion). |
| | trimSpaces | false | Boolean | Determines whether leading and trailing white spaces will be omitted from String values. Used for marshalling (XML to JSon conversion). |
| | skipNamespaces | false | Boolean | Signals whether namespaces should be ignored. By default they will be added to the JSON output using xmlns elements. Used for marshalling (XML to JSon conversion). |
| | removeNamespacePrefixes | false | Boolean | Removes the namespace prefixes from XML qualified elements so that the resulting JSON string does not contain them. Used for marshalling (XML to JSon conversion). |
| | expandableProperties | | List | With expandable properties JSON array elements are converted to XML as a sequence of repetitive XML elements with the local name equal to the JSON key for example: number: 123 normally converted to: 123 (where e can be modified by setting elementName) would instead translate to 123 if number is set as an expandable property Used for unmarshalling (JSON to XML conversion). |
| | typeHints | | String | Adds type hints to the resulting XML to aid conversion back to JSON. Used for unmarshalling (JSON to XML conversion). |
| | contentTypeHeader | false | Boolean | Whether the data format should set the Content-Type header with the type from the data format if the data format is capable of doing so. For example application/xml for data formats marshalling to XML or application/json for data formats marshalling to JSon etc. |
| |======================================================================= |
| // dataformat options: END |
| |
| ### Basic Usage with Java DSL |
| |
| #### Explicitly instantiating the data format |
| |
| Just instantiate the `XmlJsonDataFormat` from package |
| `org.apache.camel.dataformat.xmljson`. Make sure you have installed the |
| `camel-xmljson` feature (if running on OSGi) or that you've included |
| `camel-xmljson-{version}.jar` and its transitive dependencies in your |
| classpath. Example initialization with a default configuration: |
| |
| [source,java] |
| ---- |
| XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat(); |
| ---- |
| |
| To tune the behaviour of the data format as per the options above, use |
| the appropriate setters: |
| |
| [source,java] |
| ---- |
| XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat(); |
| xmlJsonFormat.setEncoding("UTF-8"); |
| xmlJsonFormat.setForceTopLevelObject(true); |
| xmlJsonFormat.setTrimSpaces(true); |
| xmlJsonFormat.setRootName("newRoot"); |
| xmlJsonFormat.setSkipNamespaces(true); |
| xmlJsonFormat.setRemoveNamespacePrefixes(true); |
| xmlJsonFormat.setExpandableProperties(Arrays.asList("d", "e")); |
| ---- |
| |
| Once you've instantiated the data format, the next step is to actually |
| use the it from within the `marshal()` and `unmarshal()` DSL elements: |
| |
| [source,java] |
| ---- |
| // from XML to JSON |
| from("direct:marshal").marshal(xmlJsonFormat).to("mock:json"); |
| // from JSON to XML |
| from("direct:unmarshal").unmarshal(xmlJsonFormat).to("mock:xml"); |
| ---- |
| |
| #### Defining the data format in-line |
| |
| Alternatively, you can define the data format inline by using the |
| `xmljson()` DSL element: |
| |
| [source,java] |
| ---- |
| // from XML to JSON - inline dataformat |
| from("direct:marshalInline").marshal().xmljson().to("mock:jsonInline"); |
| // from JSON to XML - inline dataformat |
| from("direct:unmarshalInline").unmarshal().xmljson().to("mock:xmlInline"); |
| ---- |
| |
| If you wish, you can even pass in a `Map<String, String>` to the inline |
| methods to provide custom options: |
| |
| [source,java] |
| ---- |
| Map<String, String> xmlJsonOptions = new HashMap<String, String>(); |
| xmlJsonOptions.put(org.apache.camel.model.dataformat.XmlJsonDataFormat.ENCODING, "UTF-8"); |
| xmlJsonOptions.put(org.apache.camel.model.dataformat.XmlJsonDataFormat.ROOT_NAME, "newRoot"); |
| xmlJsonOptions.put(org.apache.camel.model.dataformat.XmlJsonDataFormat.SKIP_NAMESPACES, "true"); |
| xmlJsonOptions.put(org.apache.camel.model.dataformat.XmlJsonDataFormat.REMOVE_NAMESPACE_PREFIXES, "true"); |
| xmlJsonOptions.put(org.apache.camel.model.dataformat.XmlJsonDataFormat.EXPANDABLE_PROPERTIES, "d e"); |
| |
| // from XML to JSON - inline dataformat w/ options |
| from("direct:marshalInlineOptions").marshal().xmljson(xmlJsonOptions).to("mock:jsonInlineOptions"); |
| // form JSON to XML - inline dataformat w/ options |
| from("direct:unmarshalInlineOptions").unmarshal().xmljson(xmlJsonOptions).to("mock:xmlInlineOptions"); |
| ---- |
| |
| ### Basic usage with Spring or Blueprint DSL |
| |
| Within the `<dataFormats>` block, simply configure an `xmljson` element |
| with unique IDs: |
| |
| [source,xml] |
| ---- |
| <dataFormats> |
| <xmljson id="xmljson"/> |
| <xmljson id="xmljsonWithOptions" forceTopLevelObject="true" trimSpaces="true" rootName="newRoot" skipNamespaces="true" |
| removeNamespacePrefixes="true" expandableProperties="d e"/> |
| </dataFormats> |
| ---- |
| |
| Then you simply refer to the data format object within your |
| `<marshal />` and `<unmarshal />` DSLs: |
| |
| [source,xml] |
| ---- |
| <route> |
| <from uri="direct:marshal"/> |
| <marshal ref="xmljson"/> |
| <to uri="mock:json" /> |
| </route> |
| |
| <route> |
| <from uri="direct:unmarshalWithOptions"/> |
| <unmarshal ref="xmljsonWithOptions"/> |
| <to uri="mock:xmlWithOptions"/> |
| </route> |
| ---- |
| |
| Enabling XML DSL autocompletion for this component is easy: just refer |
| to the appropriate http://camel.apache.org/xml-reference.html[Schema |
| locations], depending on whether you're using |
| http://camel.apache.org/schema/spring/[Spring] or |
| http://camel.apache.org/schema/blueprint/[Blueprint] DSL. Remember that |
| this data format is available from Camel 2.10 onwards, so only schemas |
| from that version onwards will include these new XML elements and |
| attributes. |
| |
| The syntax with link:using-osgi-blueprint-with-camel.html[Blueprint] is |
| identical to that of the Spring DSL. Just ensure the correct namespaces |
| and schemaLocations are in use. |
| |
| ### Namespace mappings |
| |
| XML has namespaces to fully qualify elements and attributes; JSON |
| doesn't. You need to take this into account when performing XML-JSON |
| conversions. |
| |
| To bridge the gap, http://json-lib.sourceforge.net/[Json-lib] has an |
| option to bind namespace declarations in the form of prefixes and |
| namespace URIs to XML output elements while unmarshalling (i.e. |
| converting from JSON to XML). For example, provided the following JSON |
| string: |
| |
| [source,json] |
| ---- |
| { "pref1:a": "value1", "pref2:b": "value2" } |
| ---- |
| |
| you can ask Json-lib to output namespace declarations on elements |
| `pref1:a` and `pref2:b` to bind the prefixes `pref1` and `pref2` to |
| specific namespace URIs. |
| |
| To use this feature, simply create |
| `XmlJsonDataFormat.NamespacesPerElementMapping` objects and add them to |
| the `namespaceMappings` option (which is a `List`). |
| |
| The `XmlJsonDataFormat.NamespacesPerElementMapping` holds an element |
| name and a Map of [prefix => namespace URI]. To facilitate mapping |
| multiple prefixes and namespace URIs, the |
| `NamespacesPerElementMapping(String element, String pipeSeparatedMappings)` |
| constructor takes a String-based pipe-separated sequence of [prefix, |
| namespaceURI] pairs in the following way: |
| `|ns2|http://camel.apache.org/personalData|ns3|http://camel.apache.org/personalData2|`. |
| |
| In order to define a default namespace, just leave the corresponding key |
| field empty: |
| `|ns1|http://camel.apache.org/test1||http://camel.apache.org/default|`. |
| |
| Binding namespace declarations to an element name = empty string will |
| attach those namespaces to the root element. |
| |
| The full code would look like that: |
| |
| [source,java] |
| ---- |
| XmlJsonDataFormat namespacesFormat = new XmlJsonDataFormat(); |
| List<XmlJsonDataFormat.NamespacesPerElementMapping> namespaces = new ArrayList<XmlJsonDataFormat.NamespacesPerElementMapping>(); |
| namespaces.add(new XmlJsonDataFormat. |
| NamespacesPerElementMapping("", "|ns1|http://camel.apache.org/test1||http://camel.apache.org/default|")); |
| namespaces.add(new XmlJsonDataFormat. |
| NamespacesPerElementMapping("surname", "|ns2|http://camel.apache.org/personalData|" + |
| "ns3|http://camel.apache.org/personalData2|")); |
| namespacesFormat.setNamespaceMappings(namespaces); |
| namespacesFormat.setRootElement("person"); |
| ---- |
| |
| And you can achieve the same in Spring DSL. |
| |
| #### Example |
| |
| Using the namespace bindings in the Java snippet above on the following |
| JSON string: |
| |
| [source,json] |
| ---- |
| { "name": "Raul", "surname": "Kripalani", "f": true, "g": null} |
| ---- |
| |
| |
| |
| Would yield the following XML: |
| |
| [source,xml] |
| ---- |
| <person xmlns="http://camel.apache.org/default" xmlns:ns1="http://camel.apache.org/test1"> |
| <f>true</f> |
| <g null="true"/> |
| <name>Raul</name> |
| <surname xmlns:ns2="http://camel.apache.org/personalData" xmlns:ns3="http://camel.apache.org/personalData2">Kripalani</surname> |
| </person> |
| ---- |
| |
| Remember that the JSON spec defines a JSON object as follows: |
| |
| _________________________________________________________ |
| An object is an unordered set of name/value pairs. [...]. |
| _________________________________________________________ |
| |
| That's why the elements are in a different order in the output XML. |
| |
| ### Dependencies |
| |
| To use the link:xmljson.html[XmlJson] dataformat in your camel routes |
| you need to add the following dependency to your pom: |
| |
| [source,xml] |
| ---- |
| <dependency> |
| <groupId>org.apache.camel</groupId> |
| <artifactId>camel-xmljson</artifactId> |
| <version>x.x.x</version> |
| <!-- Use the same version as camel-core, but remember that this component is only available from 2.10 onwards --> |
| </dependency> |
| |
| <!-- And also XOM must be included. XOM cannot be included by default due to an incompatible |
| license with ASF; so add this manually --> |
| <dependency> |
| <groupId>xom</groupId> |
| <artifactId>xom</artifactId> |
| <version>1.2.5</version> |
| </dependency> |
| ---- |
| |
| ### See Also |
| |
| * link:data-format.html[Data Format] |
| * http://json-lib.sourceforge.net/[json-lib] |