A customer typed "" in their notes field. It broke 200 XML orders and I spent 3 hours finding a one-line fix.
TL;DR
- User-generated text with angle brackets (
<,>) breaks XML output — the parser treats them as tags - The
<~metadata operator with{cdata: true}wraps content in CDATA sections - CDATA preserves angle brackets as literal text:
<![CDATA[text with <VIP>]]> - The
<~operator requires DataWeave 2.5 (Mule 4.5+) - JSON output silently ignores cdata metadata — no error, no effect
The Problem: Valid JSON, Invalid XML
We had a Mule flow converting customer orders from JSON to XML for an ERP. Worked for 6 months. Then 200 orders got rejected.
The customer's notes field:
{
"customer": {
"name": "Alice Chen",
"email": "alice@example.com",
"notes": "Preferred customer since 2020 <VIP>"
},
"orderId": "ORD-12345"
}
The DataWeave transform:
%dw 2.0
output application/xml
---
order @(id: payload.orderId): {
customer @(class: "Person", source: "CRM"): {
name: payload.customer.name,
email: payload.customer.email,
notes: payload.customer.notes
}
}
Output XML:
<order id="ORD-12345">
<customer class="Person" source="CRM">
<name>Alice Chen</name>
<notes>Preferred customer since 2020 <VIP></notes>
</customer>
</order>
The <VIP> in the notes became an XML opening tag. No closing </VIP> tag. Invalid XML. The ERP rejected the entire batch.
100 production-ready DataWeave patterns with tests: mulesoft-cookbook on GitHub
The Fix: The <~ Metadata Operator
%dw 2.0
output application/xml
---
order @(id: payload.orderId): {
customer @(class: "Person", source: "CRM"): {
name: payload.customer.name,
email: payload.customer.email,
notes: payload.customer.notes <~ {cdata: true}
}
}
Output:
<order id="ORD-12345">
<customer class="Person" source="CRM">
<name>Alice Chen</name>
<notes><![CDATA[Preferred customer since 2020 <VIP>]]></notes>
</customer>
</order>
The <~ operator attaches metadata to a value without changing its type. {cdata: true} tells the XML writer to wrap the content in a CDATA section. Angle brackets preserved. Valid XML.
The @() Syntax for XML Attributes
The @() syntax adds XML attributes to elements:
customer @(class: "Person", source: "CRM"): { ... }
Produces: <customer class="Person" source="CRM">. Attributes come from your data, not hardcoded in the schema.
Trap 1: <~ Only Works for XML Output
I tried using <~ {cdata: true} on a JSON API response. Nothing happened. No error. No warning. The output was identical with and without the <~.
The cdata metadata is only read by the XML writer. JSON, CSV, and other formats ignore it silently.
Trap 2: Requires DataWeave 2.5
The <~ operator was introduced in DataWeave 2.5 (Mule 4.5+). On older runtimes, it throws a parse error.
Before <~, the approach was:
notes: payload.customer.notes as String {class: "cdata"}
This works on older runtimes but also coerces the type. <~ is cleaner because it only attaches metadata — the value type stays unchanged.
What I Do Now
Any field going to XML that could contain user-generated content gets <~ {cdata: true}:
- Customer notes
- Product descriptions
- Address fields (street addresses with unit symbols like #)
- Comment fields from ticketing systems
I also run a pre-transformation check: scan text fields for <, >, &. If found, log a warning and ensure CDATA wrapping is active.
100 patterns with MUnit tests: github.com/shakarbisetty/mulesoft-cookbook
60-second video walkthroughs: youtube.com/@SanThaParv
Top comments (0)