diff --git a/packages/nodes-base/nodes/Html/Html.node.ts b/packages/nodes-base/nodes/Html/Html.node.ts
index 10d3e75e9ce80..f83ebb9318361 100644
--- a/packages/nodes-base/nodes/Html/Html.node.ts
+++ b/packages/nodes-base/nodes/Html/Html.node.ts
@@ -5,12 +5,15 @@ import type {
INodeType,
INodeTypeDescription,
IDataObject,
+ INodeProperties,
} from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import { placeholder } from './placeholder';
import { getValue } from './utils';
import type { IValueData } from './types';
-import { getResolvables } from '@utils/utilities';
+import { getResolvables, sanitazeDataPathKey } from '@utils/utilities';
+
+import get from 'lodash/get';
export const capitalizeHeader = (header: string, capitalize?: boolean) => {
if (!capitalize) return header;
@@ -21,13 +24,97 @@ export const capitalizeHeader = (header: string, capitalize?: boolean) => {
.join(' ');
};
+const extractionValuesCollection: INodeProperties = {
+ displayName: 'Extraction Values',
+ name: 'extractionValues',
+ placeholder: 'Add Value',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ default: {},
+ options: [
+ {
+ name: 'values',
+ displayName: 'Values',
+ values: [
+ {
+ displayName: 'Key',
+ name: 'key',
+ type: 'string',
+ default: '',
+ description: 'The key under which the extracted value should be saved',
+ },
+ {
+ displayName: 'CSS Selector',
+ name: 'cssSelector',
+ type: 'string',
+ default: '',
+ placeholder: '.price',
+ description: 'The CSS selector to use',
+ },
+ {
+ displayName: 'Return Value',
+ name: 'returnValue',
+ type: 'options',
+ options: [
+ {
+ name: 'Attribute',
+ value: 'attribute',
+ description: 'Get an attribute value like "class" from an element',
+ },
+ {
+ name: 'HTML',
+ value: 'html',
+ description: 'Get the HTML the element contains',
+ },
+ {
+ name: 'Text',
+ value: 'text',
+ description: 'Get only the text content of the element',
+ },
+ {
+ name: 'Value',
+ value: 'value',
+ description: 'Get value of an input, select or textarea',
+ },
+ ],
+ default: 'text',
+ description: 'What kind of data should be returned',
+ },
+ {
+ displayName: 'Attribute',
+ name: 'attribute',
+ type: 'string',
+ displayOptions: {
+ show: {
+ returnValue: ['attribute'],
+ },
+ },
+ default: '',
+ placeholder: 'class',
+ description: 'The name of the attribute to return the value off',
+ },
+ {
+ displayName: 'Return Array',
+ name: 'returnArray',
+ type: 'boolean',
+ default: false,
+ description:
+ 'Whether to return the values as an array so if multiple ones get found they also get returned separately. If not set all will be returned as a single string.',
+ },
+ ],
+ },
+ ],
+};
+
export class Html implements INodeType {
description: INodeTypeDescription = {
displayName: 'HTML',
name: 'html',
icon: 'file:html.svg',
group: ['transform'],
- version: 1,
+ version: [1, 1.1],
subtitle: '={{ $parameter["operation"] }}',
description: 'Work with HTML',
defaults: {
@@ -143,94 +230,33 @@ export class Html implements INodeType {
'Name of the JSON property in which the HTML to extract the data from can be found. The property can either contain a string or an array of strings.',
},
{
- displayName: 'Extraction Values',
- name: 'extractionValues',
- placeholder: 'Add Value',
- type: 'fixedCollection',
- typeOptions: {
- multipleValues: true,
- },
+ ...extractionValuesCollection,
displayOptions: {
show: {
operation: ['extractHtmlContent'],
+ '@version': [1],
},
},
- default: {},
- options: [
- {
- name: 'values',
- displayName: 'Values',
- values: [
- {
- displayName: 'Key',
- name: 'key',
- type: 'string',
- default: '',
- description: 'The key under which the extracted value should be saved',
- },
- {
- displayName: 'CSS Selector',
- name: 'cssSelector',
- type: 'string',
- default: '',
- placeholder: '.price',
- description: 'The CSS selector to use',
- },
- {
- displayName: 'Return Value',
- name: 'returnValue',
- type: 'options',
- options: [
- {
- name: 'Attribute',
- value: 'attribute',
- description: 'Get an attribute value like "class" from an element',
- },
- {
- name: 'HTML',
- value: 'html',
- description: 'Get the HTML the element contains',
- },
- {
- name: 'Text',
- value: 'text',
- description: 'Get only the text content of the element',
- },
- {
- name: 'Value',
- value: 'value',
- description: 'Get value of an input, select or textarea',
- },
- ],
- default: 'text',
- description: 'What kind of data should be returned',
- },
- {
- displayName: 'Attribute',
- name: 'attribute',
- type: 'string',
- displayOptions: {
- show: {
- returnValue: ['attribute'],
- },
- },
- default: '',
- placeholder: 'class',
- description: 'The name of the attribute to return the value off',
- },
- {
- displayName: 'Return Array',
- name: 'returnArray',
- type: 'boolean',
- default: false,
- description:
- 'Whether to return the values as an array so if multiple ones get found they also get returned separately. If not set all will be returned as a single string.',
- },
- ],
+ },
+ {
+ ...extractionValuesCollection,
+ default: {
+ values: [
+ {
+ key: '',
+ cssSelector: '',
+ returnValue: 'text',
+ returnArray: false,
+ },
+ ],
+ },
+ displayOptions: {
+ show: {
+ operation: ['extractHtmlContent'],
+ '@version': [{ _cnd: { gt: 1 } }],
},
- ],
+ },
},
-
{
displayName: 'Options',
name: 'options',
@@ -329,6 +355,7 @@ export class Html implements INodeType {
async execute(this: IExecuteFunctions): Promise {
const items = this.getInputData();
const operation = this.getNodeParameter('operation', 0);
+ const nodeVersion = this.getNode().typeVersion;
if (operation === 'convertToHtmlTable' && items.length) {
let table = '';
@@ -467,14 +494,27 @@ export class Html implements INodeType {
let htmlArray: string[] | string = [];
if (sourceData === 'json') {
- if (item.json[dataPropertyName] === undefined) {
- throw new NodeOperationError(
- this.getNode(),
- `No property named "${dataPropertyName}" exists!`,
- { itemIndex },
- );
+ if (nodeVersion === 1) {
+ const key = sanitazeDataPathKey(item.json, dataPropertyName);
+ if (item.json[key] === undefined) {
+ throw new NodeOperationError(
+ this.getNode(),
+ `No property named "${dataPropertyName}" exists!`,
+ { itemIndex },
+ );
+ }
+ htmlArray = item.json[key] as string;
+ } else {
+ const value = get(item.json, dataPropertyName);
+ if (value === undefined) {
+ throw new NodeOperationError(
+ this.getNode(),
+ `No property named "${dataPropertyName}" exists!`,
+ { itemIndex },
+ );
+ }
+ htmlArray = value as string;
}
- htmlArray = item.json[dataPropertyName] as string;
} else {
this.helpers.assertBinaryData(itemIndex, dataPropertyName);
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
@@ -489,7 +529,7 @@ export class Html implements INodeType {
htmlArray = [htmlArray];
}
- for (const html of htmlArray as string[]) {
+ for (const html of htmlArray) {
const $ = cheerio.load(html);
const newItem: INodeExecutionData = {
diff --git a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts
index 31943b0fbf37e..c57fafa587504 100644
--- a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts
+++ b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts
@@ -17,7 +17,7 @@ import set from 'lodash/set';
import get from 'lodash/get';
import unset from 'lodash/unset';
-import { getResolvables } from '../../../../utils/utilities';
+import { getResolvables, sanitazeDataPathKey } from '../../../../utils/utilities';
import type { SetNodeOptions, SetField } from './interfaces';
import { INCLUDE } from './interfaces';
@@ -35,28 +35,15 @@ const configureFieldHelper = (dotNotation?: boolean) => {
},
};
} else {
- const sanitazeKey = (item: IDataObject, key: string) => {
- if (item[key] !== undefined) {
- return key;
- }
-
- if (key.startsWith("['") && key.endsWith("']")) {
- key = key.slice(2, -2);
- if (item[key] !== undefined) {
- return key;
- }
- }
- return key;
- };
return {
set: (item: IDataObject, key: string, value: IDataObject) => {
- item[sanitazeKey(item, key)] = value;
+ item[sanitazeDataPathKey(item, key)] = value;
},
get: (item: IDataObject, key: string) => {
- return item[sanitazeKey(item, key)];
+ return item[sanitazeDataPathKey(item, key)];
},
unset: (item: IDataObject, key: string) => {
- delete item[sanitazeKey(item, key)];
+ delete item[sanitazeDataPathKey(item, key)];
},
};
}
diff --git a/packages/nodes-base/utils/utilities.ts b/packages/nodes-base/utils/utilities.ts
index ac07ad65d7594..deed6b9c84776 100644
--- a/packages/nodes-base/utils/utilities.ts
+++ b/packages/nodes-base/utils/utilities.ts
@@ -326,3 +326,20 @@ export function preparePairedItemDataArray(
if (Array.isArray(pairedItem)) return pairedItem;
return [pairedItem];
}
+
+export const sanitazeDataPathKey = (item: IDataObject, key: string) => {
+ if (item[key] !== undefined) {
+ return key;
+ }
+
+ if (
+ (key.startsWith("['") && key.endsWith("']")) ||
+ (key.startsWith('["') && key.endsWith('"]'))
+ ) {
+ key = key.slice(2, -2);
+ if (item[key] !== undefined) {
+ return key;
+ }
+ }
+ return key;
+};