JAXB data format
The
jaxbdata format converts XML to structured values and back, typed and optionally validated by an XML Schema (XSD), without generated Java classes.
Name: jaxb · Crate: cameleer-soap · Cargo feature: soap ·
Apache Camel: JAXB
When to use it
- Read and write XML documents that have an XSD: orders, invoices (UBL), bank statements (ISO 20022), SOAP payloads.
- Get typed values from XML: numbers, booleans and dates come out typed according to the schema, and repeated elements are always arrays even when only one is present.
- Validate XML on the way in or out and reject documents that break the contract, for example XML generated by an AI agent before it reaches a partner.
With cameleer_main::new_main() and the container image (which register cameleer-soap),
jaxb is this schema-typed binding. With cameleer-core alone, jaxb is an alias of the
schema-less Jackson XML data format.
Marshal and unmarshal
| direction | input body | output body |
|---|---|---|
| unmarshal | XML text or bytes | an object: element content keyed by child name, attributes as @name keys, values typed by the schema; with schema set the document is validated first |
| marshal | an object (or a single-key object naming the root element) | XML text, indented by default, with an XML declaration unless fragment=true |
The root element on marshal is partClass, else the single key of the body object if it
names a global element, else the single global element of the schema. Without any schema the
mapping is structural: text-only elements become strings, repeated siblings arrays,
attributes @-prefixed keys. Validation errors raise UnmarshalException or
MarshalException (both JAXBException).
Example
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element name="customer" type="xs:string"/>
<xs:element name="line" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="sku" type="xs:string"/>
<xs:element name="qty" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="express" type="xs:boolean" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>Unmarshal and validate an order. qty is an integer and line an array even with one line,
so the JSON is ready for an API or a prompt.
- route:
id: jaxb-unmarshal
from:
uri: direct:jaxb-unmarshal
steps:
- unmarshal:
jaxb:
contextPath: schemas/order.xsd
schema: schemas/order.xsd
- marshal:
json: {}<order id="7"><customer>ACME</customer><line><sku>A1</sku><qty>3</qty></line><express>true</express></order>{"@id":7,"customer":"ACME","line":[{"sku":"A1","qty":3}],"express":true}An invalid document fails with UnmarshalException. Catch it to answer the sender instead
of failing the exchange:
- route:
id: jaxb-reject
from:
uri: direct:jaxb-reject
steps:
- doTry:
steps:
- unmarshal:
jaxb:
contextPath: schemas/order.xsd
schema: schemas/order.xsd
- setBody:
simple: "accepted order ${body[@id]}"
doCatch:
- exception:
- UnmarshalException
steps:
- setBody:
simple: "rejected: ${exception.message}"<order id="8"><customer>ACME</customer><line><sku>A1</sku><qty>many</qty></line></order>rejected:
'many' is not a valid value for 'int'A valid order takes the other branch:
<order id="9"><customer>ACME</customer><line><sku>A1</sku><qty>2</qty></line></order>accepted order 9Marshal JSON into XML with the root element from the schema:
- route:
id: jaxb-marshal
from:
uri: direct:jaxb-marshal
steps:
- unmarshal:
json: {}
- marshal:
jaxb:
contextPath: schemas/order.xsd
prettyPrint: false
fragment: true{"@id": 9, "customer": "Globex", "line": [{"sku": "B2", "qty": 1}, {"sku": "C3", "qty": 4}]}<order id="9"><customer>Globex</customer><line><sku>B2</sku><qty>1</qty></line><line><sku>C3</sku><qty>4</qty></line></order>Rust DSL
b.from("direct:jaxb-rust")
.unmarshal(DataFormatDefinition::new("jaxb").option("contextPath", "schemas/order.xsd"))
.marshal_json();Options
| option | default | description |
|---|---|---|
contextPath | (none) | Schema(s) used for typing: XSD locations separated by , or ; (path, file:, classpath:, #bean, or inline XSD), or a .properties descriptor with schema= and prefix.<p>=<namespace> lines. |
schema | (none) | XSD used to validate on unmarshal and marshal (also used for typing when contextPath gives none). |
partClass | (none) | Root element for marshal: {namespace}local or local (with partNamespace). |
partNamespace | (none) | Namespace of partClass. |
ignoreJAXBElement | true | Unmarshal returns the root element's content; false wraps it as {root: content}. |
prettyPrint | true | Indent the output, as Camel does. |
fragment | false | Omit the XML declaration. |
encoding | UTF-8 | Encoding of the declaration and output (ISO-8859-1 supported for bytes). |
namespacePrefix | (none) | Preferred prefixes: uri=prefix,uri2=prefix2 or a #bean map. |
attributePrefix | @ | Key prefix for attributes; plainAttributes=true uses plain keys. |
typedDates | false | Map date, dateTime, time and duration to calendar-like objects instead of strings. |
filterNonXmlChars | false | Remove characters that are illegal in XML. |
contentTypeHeader | true | Set Content-Type on marshal. |
mustBeJAXBElement, objectFactory, noNamespaceSchemaLocation, schemaLocation,
schemaSeverityLevel, jaxbProviderProperties and xmlStreamWriterWrapper are accepted for
compatibility.
Differences from Apache Camel
Camel binds XML to classes generated by xjc (contextPath is a Java package). Here
contextPath points at the XSD itself and the result is a plain object. Polymorphism follows
the schema: xsi:type selects the derived type (kept as @xsi:type), and substitution group
members bind where their head element is declared.
Common questions
How do I validate XML against an XSD while parsing it?
Set schema: path/to.xsd on the jaxb unmarshal (as in the example). For validation alone,
without conversion, use the validator component.
How do I convert XML to JSON with correct number types?
unmarshal: jaxb: {contextPath: my.xsd} then marshal: json: {}. Without a schema every
value is a string, because XML has no types of its own.
Why is a single element still an array?
The schema says maxOccurs="unbounded", so the binding always produces an array. That keeps
code that reads the value simple.
Related
- Jackson XML data format: schema-less XML mapping
- Validator component, XSLT component
- Apache Camel JAXB data format
Found a problem?
If something on this page doesn't match what Cameleer does, or you hit a bug while building
with it, please help fix it, whether you are a person or a coding agent:
open an issue that describes what you saw,
then fork the repository, fix it, add or update a test, run cargo test --workspace, and open
a pull request. CONTRIBUTING.md
explains the ground rules.