XMLMarshaller
XMLMarshaller
is a companion class to XMLSchemata implementing serialization of data objects to XML string according to a given XML schema element (normally, a complex type).
const xs = await XMLSchemata.fromFile ('wsdl_related_stuff.xsd')
const m = xs.createMarshaller (localName, namespaceURI)
const xml = m.stringify (data /*, {
// localName : 'otherThanDataRootKey',
// declaration : {encoding: 'UTF-5'},
}*/)
XMLMarshaller
can be considered a JSON to XML converter: it does the almost exactly opposite to XMLNode.toObject, with similar (but inverse) structure transformations.
-
boolean
values are always written asfalse
ortrue
; a mapping is predefined for strings'0'/'1'
,'false'/'true'
,'N'/'Y'
, other values are subject to standardtoBoolean
; - if a Number or a BigInt is supplied for a
date
ordateTime
field, it's used as an argument for theDate
constructor (number of milliseconds since 1970-01-01); - for a
date
field, any string of length 10 is passed through unchecked (it's expected to de inYYYY-MM-DD
format, be careful), otherwise theDate
object is constructed and (re)serialized; - for
integer
and all its descendants, a BigInt or (forint
and shorter types) a Number is created, checked and then serialized; - for
float
anddouble
, a Number is created withparseFloat
, then serialized; - for
decimal
too,parseFloat
is used, but then, iffractionDigits
restriction is set, the string is formed withtoFixed
; -
QName
s are expected to be supplied as{localName, namespaceURI}
objects, for which qualified names are generated according to the current namespace map; - all other values are converted
toString
, special characters are escaped.
Attribute only elements are naturally mapped from scalar valued plain objects:
{Order: {amount: 1, price: 2.34}} // <Order amount="1" price="2.34"/>
Text only child elements are normally represented by scalar properties of data objects:
{Outer: {Inner: 123}} // <Outer><Inner>123</Inner></Outer>
But how to represent data for elements with both attributes and text content? In this case, the text must be presented as a null
named pseudo attribute:
{Request: {Id: 1, null: 'HELO'}} // <Request Id="1">HELO</Request>
Some schemata (like SOAP 1.1) contain any
and anyAttribute
wildcards corresponding to XML fragments of unknown structure.
For stringify
to fill in such a wildcard, the content must be presented as a special object with null
key is provided:
xs.stringify ({
Envelope: {
Body: { // contains xs:any, xs:anyAttribute
null: { // cannot be localName, so no possible confilct here
'<someRequest>CODE</someRequest>': // raw XML content to be injected as xs:any
{Id: 1 /*, ...*/} // "any" attributes key/value pairs
}},
}
}
)
yields
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
<ns0:Body Id="1"><someRequest>CODE</someRequest></ns0:Body>
</ns0:Envelope>
In application code, such values may be produced with the XMLSchemata.any
convenience method.
- Probably forever:
- Virtually no validation of any kind
- except for edge cases like a
true
value for adateTime
field: then, XMLMarshaller will throw an error - and, maybe, later, for exotic scalar types like gDay)
- except for edge cases like a
- No
xsi:type
polymorphism
- Virtually no validation of any kind
- Minor performance issues not to be fixed shortly:
- Elements with zero length content have explicit closing tags, self enclosing is not used.
-
"
are escaped as"
not only in attribute values, but in text nodes too.
- Pesky things
-
choice
is implemented as an alias tosequence
: if data are supplied for two or more branches of onechoice
, the result will be invalid. -
hexBinary
andbase64Binary
encoding should be supported forBuffer
values.
-
Generates the XML declaration pseudo-tag.
const decl = XMLMarshaller.declaration ({
version: 3.14159, // '1.0' by default
encoding: 'UTF-6', // no default; may be missing
standalone: 'no', // no default; may be missing
})