Skip to content

Commit e7ed5d4

Browse files
author
Dmitry Ovsyanko
committed
chapter_05 rewrite
1 parent 440210a commit e7ed5d4

1 file changed

Lines changed: 12 additions & 22 deletions

File tree

doc_src/src/chapter_05.md

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
11
# 5. Mapping XML Nodes to Plain Objects
22

3-
Converting XML to plain JavaScript objects is a frequent requirement when integrating with modern APIs, databases, or frontend frameworks. `node-xml-toolkit` provides a focused utility for this task: `XMLNode.toObject()`, powered internally by the `MoxyLikeJsonEncoder` module.
3+
Funny thing: while XML still stands behind the *“X”* in [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) and [XHR](https://en.wikipedia.org/wiki/XMLHttpRequest), it was almost completely replaced by [JSON](https://www.json.org/json-en.html) so long ago that one could say it was never really used there. So, a fortiori, a native JS library for XML must have a means for transforming parsed DOM fragments into equivalent hierarchies of plain Objects.
44

5-
> **Clarification**: Despite its name, `XMLNode.toObject()` is not an instance method on `XMLNode`. It is a standalone function exported for convenience, designed primarily to serve as a mapper function for `XMLReader`.
6-
7-
## 5.1 Purpose and Design Philosophy
8-
9-
`XMLNode.toObject()` transforms an `XMLNode` tree into a plain, `JSON.stringify`-ready JavaScript object. Its design prioritizes:
10-
11-
- **Simplicity**: Minimal options, predictable output.
12-
- **Streaming compatibility**: Returns a function suitable for `XMLReader`'s `map` option.
13-
- **Data-processing focus**: Merges attributes with child elements; does not preserve document order or mixed content.
14-
15-
It is **not** intended for general-purpose XML transformation tasks where namespace fidelity, processing instructions, or exact node ordering matter. For those cases, work directly with `XMLNode` methods like `detach()` or traverse the tree manually.
5+
Alas, due to a well known sort of "impedance mismatch", this problem has no general solution. While JS[ON] data model is nearly ideal for business logic, XML DOM has some extra degrees of freedom that make the automatic conversion impossible. There is no way to map *mixed content* (distinguishable sequential text fragments intermitted by sibling elements–all this inside a parent element having attributes) to a plain JSON Object without either losing data or bloating the result with redundant elements requiring an immediate transformation to clean them up.
166

17-
The historical name of an internal class `MoxyLikeJsonEncoder` reflects that the core behavior draws loose inspiration from [EclipseLink MOXy](https://eclipse.dev/eclipselink/#moxy)'s JSON binding conventions—but it is a lightweight, independent implementation with its own rules.
18-
19-
## 5.2 Usage Pattern
7+
`node-xml-toolkit` takes a practical approach to this problem: if offers a solution that works for most _data centric_ XML (like DB dumps–opposed to _document centric_ things like [OOXML](https://ooxml.info/docs/)).
208

9+
## 5.1 Usage Pattern
2110
### Direct invocation on a parsed node
2211

2312
```javascript
2413
const { XMLParser, XMLNode } = require('xml-toolkit')
2514

2615
const parser = new XMLParser()
27-
const doc = parser.process('<root><item id="1">value</item></root>')
16+
const doc = parser.process('<root><item id="1"><value>3.14<value></item></root>')
2817

2918
const result = XMLNode.toObject({ wrap: true })(doc)
30-
// result: { root: { item: { id: "1", "#text": "value" } } }
19+
// result: { root: { item: { id: "1", "value": "3.14" } } }
3120
```
3221

22+
> **Clarification**: Despite its name, `XMLNode.toObject()` is not an instance method on `XMLNode`. It is a standalone function exported for convenience, designed primarily to serve as a mapper function for `XMLReader`.
23+
3324
### As a mapper for XMLReader
3425

3526
```javascript
@@ -50,18 +41,17 @@ for await (const obj of reader.process(stream)) {
5041
}
5142
```
5243

53-
> Note: When used directly, `XMLNode.toObject(options)` returns a function that accepts an `XMLNode` and returns the transformed object.
44+
> **Note**: When used directly, `XMLNode.toObject(options)` returns a function that accepts an `XMLNode` and returns the transformed object.
5445
55-
## 5.3 Options Reference
46+
## 5.2 Options Reference
5647

5748
| Option | Default | Description |
5849
|--------|---------|-------------|
5950
| `wrap` | `false` | If `true`, output includes the root element name as a top-level key: `{ RootName: {...} }`. If `false` (default), only the content object is returned. |
6051
| `getName` | `(localName, namespaceURI) => localName` | Function to transform XML element/attribute names into JavaScript object keys. Receives `localName` and `namespaceURI`; returns the desired property name. |
6152
| `map` | `undefined` | If provided, a function applied to each resulting object (similar to `Array.prototype.map`). Useful for adding computed fields or normalizing structure. |
6253

63-
## 5.4 Transformation Rules
64-
54+
## 5.3 Transformation Rules
6555
### Top-level element handling
6656

6757
By default, the root element's name is omitted from the output:
@@ -177,7 +167,7 @@ XMLNode.toObject({
177167
→ { "{urn:example}code": "XYZ" }
178168
```
179169

180-
## 5.5 Practical Examples
170+
## 5.4 Practical Examples
181171

182172
### Example 1: Extracting a flat record list
183173

0 commit comments

Comments
 (0)