n8n-nodes-xml-plus
Version:
An alternative XML node based on fast-xml-parser as opposed to xml2js that's used in the built-in XML node. Designed for performance with larger datasets as well as adding additional customizability.
235 lines • 10.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.XmlPlus = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const fast_xml_parser_1 = require("fast-xml-parser");
const XmlPlusOptions_1 = require("./XmlPlusOptions");
class XmlPlus {
constructor() {
this.description = {
displayName: 'XML Plus',
name: 'xmlPlus',
description: 'Convert data to and from XML (community node)',
icon: 'file:XmlPlus.svg',
group: [],
version: 1,
defaults: {
name: 'XML Plus',
},
inputs: ["main"],
outputs: ["main"],
properties: [{
displayName: 'Operation',
name: 'operation',
description: 'The conversion needed for the input data',
type: 'options',
default: 'xmlToJson',
noDataExpression: true,
options: [{
name: 'JSON to XML',
value: 'jsonToXml',
description: 'Converts data from JSON to XML',
action: 'Convert JSON to XML',
},
{
name: 'XML to JSON',
value: 'xmlToJson',
description: 'Converts data from XML to JSON',
action: 'Convert XML to JSON',
},
{
name: 'Validate XML',
value: 'validateOnly',
description: 'Validates XML without conversion',
action: 'Validate XML',
},
],
},
{
displayName: 'Use Entire JSON',
name: 'useEntireJson',
description: "Whether to use the full incoming JSON or the 'Input Property'",
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: ['jsonToXml'],
},
},
},
{
displayName: 'Input Property',
name: 'inputProperty',
description: 'Name of the property to be converted',
type: 'string',
default: 'data',
required: true,
requiresDataPath: 'single',
displayOptions: {
hide: {
useEntireJson: [true],
},
},
},
{
displayName: 'Output Property',
name: 'outputProperty',
description: 'Name of the output property where the converted data will be stored',
type: 'string',
default: 'data',
required: true,
requiresDataPath: 'single',
},
{
displayName: 'Format XML',
name: 'format',
description: 'Whether parsed XML is output as a single-line XML string or formatted using tabs and newlines',
type: 'boolean',
default: true,
displayOptions: {
show: {
operation: ['jsonToXml'],
},
},
},
{
displayName: 'Validator',
name: 'validateXml',
description: 'Whether to enable or disable XML validation on the parsed or built XML data',
type: 'boolean',
default: false,
},
...XmlPlusOptions_1.xmlPlusOptions,
],
};
}
async execute() {
const items = this.getInputData();
const operation = this.getNodeParameter('operation', 0);
const returnData = [];
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
try {
const item = items[itemIndex];
const jsonData = item.json;
const outputProperty = this.getNodeParameter('outputProperty', itemIndex);
const validateXml = this.getNodeParameter('validateXml', itemIndex);
function getNestedProperty(obj, path) {
return path.split('.').reduce((acc, key) => acc === null || acc === void 0 ? void 0 : acc[key], obj);
}
if (operation === 'xmlToJson') {
const inputProperty = this.getNodeParameter('inputProperty', itemIndex);
const xmlString = getNestedProperty(jsonData, inputProperty);
const parserOptions = this.getNodeParameter('parserOptions', itemIndex, {});
const validatorOptions = this.getNodeParameter('validatorOptions', itemIndex, {});
if (xmlString === undefined) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Item has no JSON property named "${inputProperty}"`, {
itemIndex
});
}
const parser = new fast_xml_parser_1.XMLParser({
ignoreAttributes: false,
...parserOptions
});
const json = parser.parse(xmlString);
if (validateXml) {
const validation = fast_xml_parser_1.XMLValidator.validate(xmlString, validatorOptions);
if (validation !== true) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid XML: ${validation.err.msg}`, {
itemIndex
});
}
}
returnData.push({
json: {
[outputProperty]: json,
},
pairedItem: {
item: itemIndex,
},
});
}
else if (operation === 'jsonToXml') {
const parserOptions = this.getNodeParameter('parserOptions', itemIndex, {});
const useEntireJson = this.getNodeParameter('useEntireJson', itemIndex);
const format = this.getNodeParameter('format', itemIndex);
const includeXmlDeclaration = parserOptions === null || parserOptions === void 0 ? void 0 : parserOptions.includeXmlDeclaration;
const xmlDeclarationType = parserOptions === null || parserOptions === void 0 ? void 0 : parserOptions.xmlDeclarationType;
const validatorOptions = this.getNodeParameter('validatorOptions', itemIndex, {});
const builder = new fast_xml_parser_1.XMLBuilder({
ignoreAttributes: false,
suppressBooleanAttributes: false,
format,
...parserOptions
});
let xml;
if (useEntireJson) {
xml = builder.build(jsonData);
}
else {
const inputProperty = this.getNodeParameter('inputProperty', itemIndex);
xml = builder.build(jsonData[inputProperty]);
}
if (validateXml) {
const validation = fast_xml_parser_1.XMLValidator.validate(xml, validatorOptions);
if (validation !== true) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Built XML is invalid: ${validation.err.msg}`, {
itemIndex
});
}
}
if (includeXmlDeclaration) {
let declaration = '';
switch (xmlDeclarationType) {
case 'version11':
declaration = '<?xml version="1.1" encoding="UTF-8"?>\n';
break;
case 'noEncoding':
declaration = '<?xml version="1.0"?>\n';
break;
case 'standard':
default:
declaration = '<?xml version="1.0" encoding="UTF-8"?>\n';
}
xml = declaration + xml;
}
returnData.push({
json: {
[outputProperty]: xml,
},
pairedItem: {
item: itemIndex,
},
});
}
else if (operation === 'validateOnly') {
const inputProperty = this.getNodeParameter('inputProperty', itemIndex);
const xmlString = getNestedProperty(item.json, inputProperty);
const validatorOptions = this.getNodeParameter('validatorOptions', itemIndex, {});
const validation = fast_xml_parser_1.XMLValidator.validate(xmlString, validatorOptions);
returnData.push({
json: {
[outputProperty]: {
valid: validation === true,
message: validation === true ? 'XML is valid' : validation.err.msg,
},
},
pairedItem: {
item: itemIndex
},
});
}
}
catch (error) {
if (error instanceof n8n_workflow_1.NodeOperationError) {
throw error;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown error occurred: ${error.message || error}`, {
itemIndex
});
}
}
return [returnData];
}
}
exports.XmlPlus = XmlPlus;
//# sourceMappingURL=XmlPlus.node.js.map