Chapter 373. XML JSon DataFormat (deprecated)
Chapter 373. XML JSon DataFormat (deprecated) 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 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. 373.1. Options The XML JSon dataformat supports 13 options, which are listed below. 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: 1,2,3 , 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. 373.2. Spring Boot Auto-Configuration The component supports 14 options, which are listed below. Name Description Default Type camel.dataformat.xmljson.array-name 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'. String camel.dataformat.xmljson.content-type-header 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. false Boolean camel.dataformat.xmljson.element-name Specifies the name of the XML elements representing each array element. Used for unmarshalling (JSON to XML conversion). String camel.dataformat.xmljson.enabled Enable xmljson dataformat true Boolean camel.dataformat.xmljson.encoding Sets the encoding. Used for unmarshalling (JSON to XML conversion). String camel.dataformat.xmljson.expandable-properties 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: 1,2,3 , 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). List camel.dataformat.xmljson.force-top-level-object 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' . false Boolean camel.dataformat.xmljson.namespace-lenient 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. false Boolean camel.dataformat.xmljson.remove-namespace-prefixes 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). false Boolean camel.dataformat.xmljson.root-name 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'. String camel.dataformat.xmljson.skip-namespaces 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). false Boolean camel.dataformat.xmljson.skip-whitespace Determines whether white spaces between XML elements will be regarded as text values or disregarded. Used for marshalling (XML to JSon conversion). false Boolean camel.dataformat.xmljson.trim-spaces Determines whether leading and trailing white spaces will be omitted from String values. Used for marshalling (XML to JSon conversion). false Boolean camel.dataformat.xmljson.type-hints Adds type hints to the resulting XML to aid conversion back to JSON. Used for unmarshalling (JSON to XML conversion). String ND 373.3. Basic Usage with Java DSL 373.3.1. 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-7.13.jar and its transitive dependencies in your classpath. Example initialization with a default configuration: XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat(); To tune the behaviour of the data format as per the options above, use the appropriate setters: 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 step is to actually use the it from within the marshal() and unmarshal() DSL elements: // from XML to JSON from("direct:marshal").marshal(xmlJsonFormat).to("mock:json"); // from JSON to XML from("direct:unmarshal").unmarshal(xmlJsonFormat).to("mock:xml"); 373.3.2. Defining the data format in-line Alternatively, you can define the data format inline by using the xmljson() DSL element: // 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: 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"); 373.4. Basic usage with Spring or Blueprint DSL Within the <dataFormats> block, simply configure an xmljson element with unique IDs: <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: <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 Schema locations , depending on whether you're using Spring or 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 Blueprint is identical to that of the Spring DSL. Just ensure the correct namespaces and schemaLocations are in use. 373.5. 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, 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: { "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: 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. 373.5.1. Example Using the namespace bindings in the Java snippet above on the following JSON string: { "name": "Raul", "surname": "Kripalani", "f": true, "g": null} Would yield the following 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. 373.6. Dependencies To use the XmlJson dataformat in your camel routes you need to add the following dependency to your pom: <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> 373.7. See Also Data Format json-lib
XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat(); 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")); // from XML to JSON from("direct:marshal").marshal(xmlJsonFormat).to("mock:json"); // from JSON to XML from("direct:unmarshal").unmarshal(xmlJsonFormat).to("mock:xml"); // 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"); 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"); <dataFormats> <xmljson id="xmljson"/> <xmljson id="xmljsonWithOptions" forceTopLevelObject="true" trimSpaces="true" rootName="newRoot" skipNamespaces="true" removeNamespacePrefixes="true" expandableProperties="d e"/> </dataFormats> <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> { "pref1:a": "value1", "pref2:b": "value2" } 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"); { "name": "Raul", "surname": "Kripalani", "f": true, "g": null} <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> <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>