n8n-nodes-data-mapper 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -7
- package/dist/nodes/DataMapper/DataMapper.node.d.ts +5 -0
- package/dist/nodes/DataMapper/DataMapper.node.js +396 -292
- package/dist/nodes/DataMapper/DataMapper.node.js.map +1 -1
- package/dist/nodes/DataMapper/DataMapper.node.json +19 -2
- package/dist/nodes/DataMapper/csv.d.ts +12 -0
- package/dist/nodes/DataMapper/csv.js +60 -0
- package/dist/nodes/DataMapper/csv.js.map +1 -0
- package/dist/nodes/DataMapper/mapping.d.ts +5 -0
- package/dist/nodes/DataMapper/mapping.js +114 -17
- package/dist/nodes/DataMapper/mapping.js.map +1 -1
- package/dist/nodes/DataMapper/profile.d.ts +4 -1
- package/dist/nodes/DataMapper/profile.js +175 -49
- package/dist/nodes/DataMapper/profile.js.map +1 -1
- package/dist/nodes/DataMapper/visual.d.ts +16 -0
- package/dist/nodes/DataMapper/visual.js +755 -0
- package/dist/nodes/DataMapper/visual.js.map +1 -0
- package/dist/nodes/DataMapper/xml.d.ts +1 -0
- package/dist/nodes/DataMapper/xml.js +26 -14
- package/dist/nodes/DataMapper/xml.js.map +1 -1
- package/dist/package.json +6 -3
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
[](https://github.com/SilentJMA/n8n-nodes-data-mapper/actions/workflows/ci.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
An [n8n](https://n8n.io) community node that **maps
|
|
7
|
+
An [n8n](https://n8n.io) community node that **maps whatever comes in onto a target structure** and outputs **XML, JSON or CSV**.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Paste a **target profile** (an XML/JSON/Flat File profile component, JSON Schema, sample JSON or XML, XSD, or a CSV header) and its fields appear as a target list. Then **drag fields from n8n's Input panel onto the target fields**, the same way you draw lines in a visual mapper, or let **Map Automatically** match them by name. You don't need a source profile: anything the previous node outputs can be mapped.
|
|
10
10
|
|
|
11
|
-
Use it to turn an API response into
|
|
11
|
+
Use it to turn an API response into a partner's XML order, shape database rows into a CSV export, read a supplier's XML into clean JSON, or pull the useful parts out of a large payload.
|
|
12
12
|
|
|
13
13
|
- [Screenshots](#screenshots)
|
|
14
14
|
- [Installation](#installation)
|
|
15
|
-
- [
|
|
15
|
+
- [Drag-and-drop mapping](#drag-and-drop-mapping)
|
|
16
|
+
- [Classic mode quick start](#classic-mode-quick-start)
|
|
16
17
|
- [Paths](#paths)
|
|
17
18
|
- [Parameters](#parameters)
|
|
18
19
|
- [Transforms](#transforms)
|
|
@@ -20,6 +21,7 @@ Use it to turn an API response into your internal format, shape database rows in
|
|
|
20
21
|
- [Reusable JSON definitions](#reusable-json-definitions)
|
|
21
22
|
- [Working with XML](#working-with-xml)
|
|
22
23
|
- [Examples](#examples)
|
|
24
|
+
- [Security](#security)
|
|
23
25
|
- [Compatibility](#compatibility)
|
|
24
26
|
- [Development](#development)
|
|
25
27
|
- [License](#license)
|
|
@@ -55,9 +57,81 @@ tar -xzf n8n-nodes-data-mapper-*.tgz && mv package n8n-nodes-data-mapper
|
|
|
55
57
|
|
|
56
58
|
Restart n8n afterwards.
|
|
57
59
|
|
|
58
|
-
##
|
|
60
|
+
## Drag-and-drop mapping
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
New Data Mapper nodes (node version 2) work like a visual mapper:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
INPUT panel (whatever comes in) Data Mapper (target profile)
|
|
66
|
+
─────────────────────────────── ──────────────────────────────
|
|
67
|
+
OrderID "A1" ──drag──▶ order › @id
|
|
68
|
+
Currency "eur" ──drag──▶ order › currency
|
|
69
|
+
Items[0].SKU "P-1" ──drag──▶ order › line[] › sku
|
|
70
|
+
Items[0].Qty "2" ──drag──▶ order › line[] › quantity (number)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
1. **Output Format** — pick **XML**, **JSON** or **CSV**.
|
|
74
|
+
2. **Source Data** — *Incoming Item* (default), or *XML or JSON Text in a Field* / *XML or JSON File* when the order arrives as raw text, e.g. in a `data` field.
|
|
75
|
+
3. **Source Profile** (optional) — paste the structure of the incoming data, such as a sample order. Every target field then gets a **dropdown of source fields**, like picking the source side of a line in a visual mapper. You can still switch any field to an expression.
|
|
76
|
+
4. **Target Profile** — paste the profile. Its fields load into **Target Fields** as a tree (`order › line[] › @sku`): `›` separates levels, `[]` marks a repeating element, `@` an XML attribute, `(number)` a type and `*` a required field.
|
|
77
|
+
5. **Target Fields** — for each target field, pick the source field from the dropdown (with a Source Profile), or drag a field from the **Input** panel and drop it into the box. Or set the mode to **Map Automatically** and the node matches source fields to target fields by similar names (`OrderID` → `orderId`, `Qty` → `quantity`).
|
|
78
|
+
6. Run the node.
|
|
79
|
+
|
|
80
|
+
A source profile made from a one-item sample still maps every item of a real order: when a picked field sits inside a list in the actual data (`orders.order.lines.line.sku` with several `line`s), each element becomes its own target element.
|
|
81
|
+
|
|
82
|
+
What a drop can be:
|
|
83
|
+
|
|
84
|
+
| You put in a target box | What happens |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| A field picked from the Source Profile dropdown | That field is copied across (lists included). |
|
|
87
|
+
| A dragged field, `{{ $json.OrderID }}` | That field is copied across. |
|
|
88
|
+
| A dragged field from a list, `{{ $json.Items[0].SKU }}`, on a repeating target (`line[]`) | Every element is mapped, not just the first: one `line` per item. |
|
|
89
|
+
| A dragged single field on a repeating target, e.g. `{{ $json.Currency }}` → `line[] › currency` | The value is written into every line. |
|
|
90
|
+
| Any expression, e.g. `{{ $json.Currency.toUpperCase() }}` or `{{ $now.toISO() }}` | Its result is used. Expressions work like map functions: `.trim()`, `.toUpperCase()`, `.toNumber()`, `.toDateTime().toFormat('dd/MM/yyyy')`, a lookup object `{{ ({ NL: 'Netherlands' })[$json.Country] }}`, and so on. |
|
|
91
|
+
| An expression returning a list on a repeating target, e.g. `{{ $json.Items.map(i => i.SKU) }}` | Element `n` of the list goes to element `n` of the target. |
|
|
92
|
+
| Fixed text, e.g. `n8n` | Written as-is. |
|
|
93
|
+
| Nothing | The target field is left out (turn on **Keep Empty Values** to write it empty). |
|
|
94
|
+
|
|
95
|
+
The output always follows the **order of the target profile**, which matters to XML consumers and XSD validation. Numbers and booleans are converted where the profile says so (**Convert Types From Profile**); a value that can't be converted is kept as it is instead of failing the run.
|
|
96
|
+
|
|
97
|
+
### Output
|
|
98
|
+
|
|
99
|
+
| Output Format | Output To: Item | Output To: File |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| JSON | The mapped data becomes the item | `output.json` |
|
|
102
|
+
| XML | XML text in the `xml` field | `output.xml` |
|
|
103
|
+
| CSV | CSV text in the `csv` field | `output.csv` |
|
|
104
|
+
|
|
105
|
+
CSV columns follow the profile. By default every incoming item becomes rows in **one CSV**, with a header row. A repeating target (`lines[]`) gives one row per element, with the other columns repeated.
|
|
106
|
+
|
|
107
|
+
### Options
|
|
108
|
+
|
|
109
|
+
| Option | Default | Description |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| Add Auto-Map Report | off | Adds `_autoMap` with matched and unmatched fields (Map Automatically, JSON output). |
|
|
112
|
+
| Auto-Map Minimum Confidence | 0.6 | How close names must be, 0 to 1. |
|
|
113
|
+
| Custom Synonyms | | Extra `source=target` name matches, one per line or a JSON object. |
|
|
114
|
+
| Convert Types From Profile | on | Turn values into numbers/booleans where the profile says so. |
|
|
115
|
+
| CSV Delimiter / Header Row / Line Ending | `,` / on / LF | CSV formatting. |
|
|
116
|
+
| Escape CSV Formulas | off | Put `'` in front of values starting with `=`, `+`, `-`, `@`, tab or CR, so spreadsheets don't run them as formulas (CSV injection). |
|
|
117
|
+
| Include XML Declaration | on | Start XML with `<?xml version="1.0" encoding="UTF-8"?>`. |
|
|
118
|
+
| Keep Empty Values | off | Write empty target fields instead of leaving them out. |
|
|
119
|
+
| One CSV for All Items | on | One CSV for the whole run, or one per item. |
|
|
120
|
+
| Profile Format / Source Profile Format | Detect Automatically | Force a profile type if detection guesses wrong. |
|
|
121
|
+
| Read Profile From Binary Field | | Read the profile from an uploaded file at run time (works with Map Automatically; to drag and drop, paste the profile). |
|
|
122
|
+
| Root Element | | XML root name. Defaults to the root of a sample-XML target profile. |
|
|
123
|
+
|
|
124
|
+
### Tips
|
|
125
|
+
|
|
126
|
+
- **CSV, Excel or other files coming in?** Put an **Extract from File** node first so each row becomes an item you can drag from.
|
|
127
|
+
- **Input is raw XML in a field and you can't drag from it?** Set **Source Data** to *XML or JSON Text in a Field* and paste a **Source Profile**: you then pick source fields from dropdowns.
|
|
128
|
+
- **The field list is empty?** It loads from the pasted profile. If the profile comes from an expression, n8n can't list its fields at design time: paste it, or use Map Automatically.
|
|
129
|
+
- **Changed the profile?** Use the refresh button above the target fields to reload them.
|
|
130
|
+
- Existing workflows keep the **classic mode** (node version 1) described below. Nothing changes for them.
|
|
131
|
+
|
|
132
|
+
## Classic mode quick start
|
|
133
|
+
|
|
134
|
+
Data Mapper nodes created before version 0.3.0 (node version 1) use path-based mappings with built-in transforms. Given this input item:
|
|
61
135
|
|
|
62
136
|
```json
|
|
63
137
|
{
|
|
@@ -124,7 +198,8 @@ Mappings run in order, and a later mapping to the same target overwrites an earl
|
|
|
124
198
|
| **Input Format** | *Detect Automatically* (XML when the text starts with `<`), *JSON* or *XML*. |
|
|
125
199
|
| **Define Mappings** | *Using Fields Below*, *Auto-Map From Profile*, or *Using JSON*. See [Target profiles and auto-map](#target-profiles-and-auto-map) and [Reusable JSON definitions](#reusable-json-definitions). |
|
|
126
200
|
| **Target Profile** / **Target Profile Format** | Optional. The structure to map into. See [Target profiles and auto-map](#target-profiles-and-auto-map). |
|
|
127
|
-
| **
|
|
201
|
+
| **Source Profile** / **Source Profile Format** | Optional (*Using Fields Below*). The structure of the incoming data, so each mapping can use **Source: From Source Profile** and pick the field from a dropdown. |
|
|
202
|
+
| **Mappings** | The list of mappings. Each has a **Source** (*Input Field* path, *From Source Profile* dropdown, or *Fixed Value*, which can be an expression), a **Target** (*Custom Path* you type, or *From Target Profile* picked from a dropdown), an optional **Transform**, and **If Source Is Missing**: *Leave Out* (default), *Set to Null*, *Use Default* or *Stop With Error*. |
|
|
128
203
|
| **Auto-Map Remaining Target Fields** | *Fields mode.* Fills any profile fields you did not map by hand by matching them to source fields by name. |
|
|
129
204
|
| **Unmapped Fields** | *Drop* outputs only mapped fields. *Keep* starts from a copy of the input and applies the mappings on top. |
|
|
130
205
|
| **Output Format** | *JSON* (the item), *JSON File*, *XML* (text in a field) or *XML File*. |
|
|
@@ -338,6 +413,14 @@ Keep three fields from a big payload: **Unmapped Fields** *Drop*, with mappings
|
|
|
338
413
|
|
|
339
414
|
Put one Data Mapper on each source branch, each mapping into the same target shape, then merge the branches.
|
|
340
415
|
|
|
416
|
+
## Security
|
|
417
|
+
|
|
418
|
+
- **No runtime dependencies.** The published package is only the compiled node; nothing else is installed into your n8n.
|
|
419
|
+
- **Safe XML parsing.** DTDs and entity declarations are ignored, so there are no external entities (XXE) and no entity expansion. Only the five standard entities and numeric references are decoded. Nesting deeper than 1,000 levels is rejected with a clear error.
|
|
420
|
+
- **No prototype pollution.** Field names and paths such as `__proto__` or `constructor`, whether they come from mappings, profiles, lookup tables or the data itself, are treated as plain data and never reach `Object.prototype`.
|
|
421
|
+
- **No code execution.** Mappings, profiles and lookup tables are data; the node never evaluates them. Expressions are evaluated by n8n itself, as in any other node.
|
|
422
|
+
- **CSV injection.** Turn on **Escape CSV Formulas** when the CSV will be opened in a spreadsheet and contains untrusted values.
|
|
423
|
+
|
|
341
424
|
## Compatibility
|
|
342
425
|
|
|
343
426
|
- n8n 1.x and 2.x (Nodes API version 1)
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
import { getProfileFields } from './visual';
|
|
2
3
|
export declare class DataMapper implements INodeType {
|
|
3
4
|
description: INodeTypeDescription;
|
|
4
5
|
methods: {
|
|
6
|
+
resourceMapping: {
|
|
7
|
+
getProfileFields: typeof getProfileFields;
|
|
8
|
+
};
|
|
5
9
|
loadOptions: {
|
|
10
|
+
getSourceFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
6
11
|
getTargetFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
12
|
};
|
|
8
13
|
};
|