001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.model.dataformat; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.Map; 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlList; 026import javax.xml.bind.annotation.XmlRootElement; 027 028import org.apache.camel.CamelContext; 029import org.apache.camel.model.DataFormatDefinition; 030import org.apache.camel.spi.DataFormat; 031import org.apache.camel.spi.Metadata; 032 033/** 034 * xml-json data format 035 * 036 * @version 037 */ 038@Metadata(label = "dataformat,transformation", title = "XML JSon") 039@XmlRootElement(name = "xmljson") 040@XmlAccessorType(XmlAccessType.FIELD) 041public class XmlJsonDataFormat extends DataFormatDefinition { 042 043 public static final String TYPE_HINTS = "typeHints"; 044 public static final String REMOVE_NAMESPACE_PREFIXES = "removeNamespacePrefixes"; 045 public static final String SKIP_NAMESPACES = "skipNamespaces"; 046 public static final String TRIM_SPACES = "trimSpaces"; 047 public static final String SKIP_WHITESPACE = "skipWhitespace"; 048 public static final String EXPANDABLE_PROPERTIES = "expandableProperties"; 049 public static final String ARRAY_NAME = "arrayName"; 050 public static final String ELEMENT_NAME = "elementName"; 051 public static final String ROOT_NAME = "rootName"; 052 public static final String NAMESPACE_LENIENT = "namespaceLenient"; 053 public static final String FORCE_TOP_LEVEL_OBJECT = "forceTopLevelObject"; 054 public static final String ENCODING = "encoding"; 055 056 @XmlAttribute 057 private String encoding; 058 @XmlAttribute 059 private String elementName; 060 @XmlAttribute 061 private String arrayName; 062 @XmlAttribute 063 private Boolean forceTopLevelObject; 064 @XmlAttribute 065 private Boolean namespaceLenient; 066 @XmlAttribute 067 private String rootName; 068 @XmlAttribute 069 private Boolean skipWhitespace; 070 @XmlAttribute 071 private Boolean trimSpaces; 072 @XmlAttribute 073 private Boolean skipNamespaces; 074 @XmlAttribute 075 private Boolean removeNamespacePrefixes; 076 @XmlAttribute @XmlList 077 private List<String> expandableProperties; 078 @XmlAttribute 079 private String typeHints; 080 081 public XmlJsonDataFormat() { 082 super("xmljson"); 083 } 084 085 public XmlJsonDataFormat(Map<String, String> options) { 086 super("xmljson"); 087 if (options.containsKey(ENCODING)) { 088 encoding = options.get(ENCODING); 089 } 090 if (options.containsKey(FORCE_TOP_LEVEL_OBJECT)) { 091 forceTopLevelObject = Boolean.parseBoolean(options.get(FORCE_TOP_LEVEL_OBJECT)); 092 } 093 if (options.containsKey(NAMESPACE_LENIENT)) { 094 namespaceLenient = Boolean.parseBoolean(options.get(NAMESPACE_LENIENT)); 095 } 096 if (options.containsKey(ROOT_NAME)) { 097 rootName = options.get(ROOT_NAME); 098 } 099 if (options.containsKey(ELEMENT_NAME)) { 100 elementName = options.get(ELEMENT_NAME); 101 } 102 if (options.containsKey(ARRAY_NAME)) { 103 arrayName = options.get(ARRAY_NAME); 104 } 105 if (options.containsKey(EXPANDABLE_PROPERTIES)) { 106 expandableProperties = Arrays.asList(options.get(EXPANDABLE_PROPERTIES).split(" ")); 107 } 108 if (options.containsKey(SKIP_WHITESPACE)) { 109 skipWhitespace = Boolean.parseBoolean(options.get(SKIP_WHITESPACE)); 110 } 111 if (options.containsKey(TRIM_SPACES)) { 112 trimSpaces = Boolean.parseBoolean(options.get(TRIM_SPACES)); 113 } 114 if (options.containsKey(SKIP_NAMESPACES)) { 115 skipNamespaces = Boolean.parseBoolean(options.get(SKIP_NAMESPACES)); 116 } 117 if (options.containsKey(REMOVE_NAMESPACE_PREFIXES)) { 118 removeNamespacePrefixes = Boolean.parseBoolean(options.get(REMOVE_NAMESPACE_PREFIXES)); 119 } 120 if (options.containsKey(TYPE_HINTS)) { 121 typeHints = options.get(TYPE_HINTS); 122 } 123 } 124 125 @Override 126 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 127 if (encoding != null) { 128 setProperty(camelContext, dataFormat, ENCODING, encoding); 129 } 130 131 if (forceTopLevelObject != null) { 132 setProperty(camelContext, dataFormat, FORCE_TOP_LEVEL_OBJECT, forceTopLevelObject); 133 } 134 135 if (namespaceLenient != null) { 136 setProperty(camelContext, dataFormat, NAMESPACE_LENIENT, namespaceLenient); 137 } 138 139 if (rootName != null) { 140 setProperty(camelContext, dataFormat, ROOT_NAME, rootName); 141 } 142 143 if (elementName != null) { 144 setProperty(camelContext, dataFormat, ELEMENT_NAME, elementName); 145 } 146 147 if (arrayName != null) { 148 setProperty(camelContext, dataFormat, ARRAY_NAME, arrayName); 149 } 150 151 if (expandableProperties != null && expandableProperties.size() != 0) { 152 setProperty(camelContext, dataFormat, EXPANDABLE_PROPERTIES, expandableProperties); 153 } 154 155 if (skipWhitespace != null) { 156 setProperty(camelContext, dataFormat, SKIP_WHITESPACE, skipWhitespace); 157 } 158 159 if (trimSpaces != null) { 160 setProperty(camelContext, dataFormat, TRIM_SPACES, trimSpaces); 161 } 162 163 if (skipNamespaces != null) { 164 setProperty(camelContext, dataFormat, SKIP_NAMESPACES, skipNamespaces); 165 } 166 167 if (removeNamespacePrefixes != null) { 168 setProperty(camelContext, dataFormat, REMOVE_NAMESPACE_PREFIXES, removeNamespacePrefixes); 169 } 170 171 // will end up calling the setTypeHints(String s) which does the parsing from the Enum String key to the Enum value 172 if (typeHints != null) { 173 setProperty(camelContext, dataFormat, TYPE_HINTS, typeHints); 174 } 175 176 //TODO: xmljson: element-namespace mapping is not implemented in the XML DSL 177 // depending on adoption rate of this data format, we'll make this data format NamespaceAware so that it gets 178 // the prefix-namespaceURI mappings from the context, and with a new attribute called "namespacedElements", 179 // we'll associate named elements with prefixes following a format "element1:prefix1,element2:prefix2,..." 180 } 181 182 public String getEncoding() { 183 return encoding; 184 } 185 186 /** 187 * Sets the encoding. 188 * Used for unmarshalling (JSON to XML conversion). 189 */ 190 public void setEncoding(String encoding) { 191 this.encoding = encoding; 192 } 193 194 public String getElementName() { 195 return elementName; 196 } 197 198 /** 199 * Specifies the name of the XML elements representing each array element. 200 * Used for unmarshalling (JSON to XML conversion). 201 */ 202 public void setElementName(String elementName) { 203 this.elementName = elementName; 204 } 205 206 public String getArrayName() { 207 return arrayName; 208 } 209 210 /** 211 * Specifies the name of the top-level XML element. 212 * Used for unmarshalling (JSON to XML conversion). 213 * 214 * For example, when converting [1, 2, 3], it will be output by default as <a><e>1</e><e>2</e><e>3</e></a>. 215 * By setting this option or rootName, you can alter the name of element 'a'. 216 */ 217 public void setArrayName(String arrayName) { 218 this.arrayName = arrayName; 219 } 220 221 public Boolean getForceTopLevelObject() { 222 return forceTopLevelObject; 223 } 224 225 /** 226 * Determines whether the resulting JSON will start off with a top-most element whose name matches the XML root element. 227 * Used for marshalling (XML to JSon conversion). 228 * 229 * If disabled, XML string <a><x>1</x><y>2</y></a> turns into { 'x: '1', 'y': '2' }. 230 * Otherwise, it turns into { 'a': { 'x: '1', 'y': '2' }}. 231 */ 232 public void setForceTopLevelObject(Boolean forceTopLevelObject) { 233 this.forceTopLevelObject = forceTopLevelObject; 234 } 235 236 public Boolean getNamespaceLenient() { 237 return namespaceLenient; 238 } 239 240 /** 241 * Flag to be tolerant to incomplete namespace prefixes. 242 * Used for unmarshalling (JSON to XML conversion). 243 * In most cases, json-lib automatically changes this flag at runtime to match the processing. 244 */ 245 public void setNamespaceLenient(Boolean namespaceLenient) { 246 this.namespaceLenient = namespaceLenient; 247 } 248 249 public String getRootName() { 250 return rootName; 251 } 252 253 /** 254 * Specifies the name of the top-level element. 255 * Used for unmarshalling (JSON to XML conversion). 256 * 257 * 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). 258 * If set to 'root', the JSON string { 'x': 'value1', 'y' : 'value2' } would turn 259 * into <root><x>value1</x><y>value2</y></root>, otherwise the 'root' element would be named 'o'. 260 */ 261 public void setRootName(String rootName) { 262 this.rootName = rootName; 263 } 264 265 public Boolean getSkipWhitespace() { 266 return skipWhitespace; 267 } 268 269 /** 270 * Determines whether white spaces between XML elements will be regarded as text values or disregarded. 271 * Used for marshalling (XML to JSon conversion). 272 */ 273 public void setSkipWhitespace(Boolean skipWhitespace) { 274 this.skipWhitespace = skipWhitespace; 275 } 276 277 public Boolean getTrimSpaces() { 278 return trimSpaces; 279 } 280 281 /** 282 * Determines whether leading and trailing white spaces will be omitted from String values. 283 * Used for marshalling (XML to JSon conversion). 284 */ 285 public void setTrimSpaces(Boolean trimSpaces) { 286 this.trimSpaces = trimSpaces; 287 } 288 289 public Boolean getSkipNamespaces() { 290 return skipNamespaces; 291 } 292 293 /** 294 * Signals whether namespaces should be ignored. By default they will be added to the JSON output using @xmlns elements. 295 * Used for marshalling (XML to JSon conversion). 296 */ 297 public void setSkipNamespaces(Boolean skipNamespaces) { 298 this.skipNamespaces = skipNamespaces; 299 } 300 301 public Boolean getRemoveNamespacePrefixes() { 302 return removeNamespacePrefixes; 303 } 304 305 /** 306 * Removes the namespace prefixes from XML qualified elements, so that the resulting JSON string does not contain them. 307 * Used for marshalling (XML to JSon conversion). 308 */ 309 public void setRemoveNamespacePrefixes(Boolean removeNamespacePrefixes) { 310 this.removeNamespacePrefixes = removeNamespacePrefixes; 311 } 312 313 public List<String> getExpandableProperties() { 314 return expandableProperties; 315 } 316 317 /** 318 * With expandable properties, JSON array elements are converted to XML as a sequence of repetitive XML elements 319 * with the local name equal to the JSON key, for example: { number: 1,2,3 }, normally converted to: 320 * <number><e>1</e><e>2</e><e>3</e></number> (where e can be modified by setting elementName), would instead 321 * translate to <number>1</number><number>2</number><number>3</number>, if "number" is set as an expandable property 322 * Used for unmarshalling (JSON to XML conversion). 323 */ 324 public void setExpandableProperties(List<String> expandableProperties) { 325 this.expandableProperties = expandableProperties; 326 } 327 328 public String getTypeHints() { 329 return typeHints; 330 } 331 332 /** 333 * Adds type hints to the resulting XML to aid conversion back to JSON. 334 * Used for unmarshalling (JSON to XML conversion). 335 */ 336 public void setTypeHints(String typeHints) { 337 this.typeHints = typeHints; 338 } 339 340}