n8n-nodes-data-mapper 0.2.0 → 0.4.0

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 CHANGED
@@ -4,15 +4,16 @@
4
4
  [![CI](https://github.com/SilentJMA/n8n-nodes-data-mapper/actions/workflows/ci.yml/badge.svg)](https://github.com/SilentJMA/n8n-nodes-data-mapper/actions/workflows/ci.yml)
5
5
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
6
 
7
- An [n8n](https://n8n.io) community node that **maps data from one structure to another**. Rename and nest fields, map whole arrays with `[*]`, convert types, format dates, translate codes with lookup tables, and convert between **JSON and XML**, all in one node.
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
- Load a **target profile** (a profile component exported as XML/JSON/Flat File, JSON Schema, sample JSON/XML, XSD or a CSV header) — paste it or upload it — to pick target fields from a dropdown, or let **auto-map** match source fields to the target for you.
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 your internal format, shape database rows into a request payload, read a supplier's XML into clean JSON, or pull just the useful parts out of a large payload.
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
- - [Quick start](#quick-start)
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,80 @@ tar -xzf n8n-nodes-data-mapper-*.tgz && mv package n8n-nodes-data-mapper
55
57
 
56
58
  Restart n8n afterwards.
57
59
 
58
- ## Quick start
60
+ ## Drag-and-drop mapping
59
61
 
60
- Given this input item:
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
+ | Convert Types From Profile | on | Turn values into numbers/booleans where the profile says so. |
114
+ | CSV Delimiter / Header Row / Line Ending | `,` / on / LF | CSV formatting. |
115
+ | Escape CSV Formulas | off | Put `'` in front of values starting with `=`, `+`, `-`, `@`, tab or CR, so spreadsheets don't run them as formulas (CSV injection). |
116
+ | Include XML Declaration | on | Start XML with `<?xml version="1.0" encoding="UTF-8"?>`. |
117
+ | Keep Empty Values | off | Write empty target fields instead of leaving them out. |
118
+ | One CSV for All Items | on | One CSV for the whole run, or one per item. |
119
+ | Profile Format / Source Profile Format | Detect Automatically | Force a profile type if detection guesses wrong. |
120
+ | 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). |
121
+ | Root Element | | XML root name. Defaults to the root of a sample-XML target profile. |
122
+
123
+ ### Tips
124
+
125
+ - **CSV, Excel or other files coming in?** Put an **Extract from File** node first so each row becomes an item you can drag from.
126
+ - **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.
127
+ - **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.
128
+ - **Changed the profile?** Use the refresh button above the target fields to reload them.
129
+ - Existing workflows keep the **classic mode** (node version 1) described below. Nothing changes for them.
130
+
131
+ ## Classic mode quick start
132
+
133
+ 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
134
 
62
135
  ```json
63
136
  {
@@ -124,7 +197,8 @@ Mappings run in order, and a later mapping to the same target overwrites an earl
124
197
  | **Input Format** | *Detect Automatically* (XML when the text starts with `<`), *JSON* or *XML*. |
125
198
  | **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
199
  | **Target Profile** / **Target Profile Format** | Optional. The structure to map into. See [Target profiles and auto-map](#target-profiles-and-auto-map). |
127
- | **Mappings** | The list of mappings. Each has a **Source** (*Input Field* path 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*. |
200
+ | **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. |
201
+ | **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
202
  | **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
203
  | **Unmapped Fields** | *Drop* outputs only mapped fields. *Keep* starts from a copy of the input and applies the mappings on top. |
130
204
  | **Output Format** | *JSON* (the item), *JSON File*, *XML* (text in a field) or *XML File*. |
@@ -338,6 +412,14 @@ Keep three fields from a big payload: **Unmapped Fields** *Drop*, with mappings
338
412
 
339
413
  Put one Data Mapper on each source branch, each mapping into the same target shape, then merge the branches.
340
414
 
415
+ ## Security
416
+
417
+ - **No runtime dependencies.** The published package is only the compiled node; nothing else is installed into your n8n.
418
+ - **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.
419
+ - **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`.
420
+ - **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.
421
+ - **CSV injection.** Turn on **Escape CSV Formulas** when the CSV will be opened in a spreadsheet and contains untrusted values.
422
+
341
423
  ## Compatibility
342
424
 
343
425
  - 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
  };