-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revise Write Xml #31
Revise Write Xml #31
Changes from all commits
d91bc8b
47679fd
bcac14c
3107114
2089afc
1ea83ea
edd4054
d5a244f
c688c1c
f10852c
4fa4198
df2d06c
542415e
b4167a6
9ccf2e8
3ee6417
681e979
d084a00
2b0d7a1
c2c0f1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
{ | ||
"title": "XML", | ||
"description": "Component to work with XML files", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll change that back. I guess that component level descriptions still appear even though action/trigger level descriptions are not longer rendered. Asking for follow up: https://elasticio.slack.com/archives/C6G1E4WB1/p1587374522293600 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Platform issue: https://github.com/elasticio/elasticio/issues/3816 |
||
"help": { | ||
"link": "/components/xml/", | ||
"description": "Component to convert between XML and JSON data" | ||
}, | ||
"description": "Component to convert between XML and JSON data", | ||
"buildType": "docker", | ||
"actions": { | ||
"xmlToJson": { | ||
|
@@ -14,11 +18,69 @@ | |
}, | ||
"jsonToXml": { | ||
"title": "JSON to XML", | ||
"main": "./lib/actions/jsonToXml.js", | ||
"main": "./lib/actions/jsonToXmlOld.js", | ||
"deprecated": true, | ||
"description": "Takes the body of message passed into the component and converts to generic XML string", | ||
"metadata": { | ||
"in": {}, | ||
"out": "./lib/schemas/jsonToXml.out.json" | ||
"out": "./lib/schemas/jsonToXmlOld.out.json" | ||
} | ||
}, | ||
"jsonToXmlV2": { | ||
"title": "JSON to XML", | ||
"main": "./lib/actions/jsonToXml.js", | ||
"help": { | ||
"link": "#json-to-xml", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. after docs on docs.elastic.io updated would need to check if this link still valid |
||
"description": "Takes the result of a JSONata expression and creates corresponding XML as either a string or an attachment" | ||
}, | ||
"fields": { | ||
"uploadToAttachment": { | ||
"order": 3, | ||
"label": "Upload XML as file to attachments", | ||
"viewClass": "CheckBoxView" | ||
}, | ||
"excludeXmlHeader": { | ||
"order": 2, | ||
"label": "Exclude XML Header/Description", | ||
"viewClass": "CheckBoxView" | ||
}, | ||
"headerStandalone": { | ||
"order": 1, | ||
"label": "Is the XML file standalone", | ||
"viewClass": "CheckBoxView" | ||
} | ||
}, | ||
"metadata": { | ||
"in": { | ||
"type": "object", | ||
"properties": { | ||
"input": { | ||
"title": "JSON to convert", | ||
"type": "object", | ||
"required": true | ||
} | ||
} | ||
}, | ||
"out": { | ||
"type": "object", | ||
"properties": { | ||
"xmlString": { | ||
"type": "string", | ||
"required": false, | ||
"title": "XML String" | ||
}, | ||
"attachmentUrl": { | ||
"title": "Attachment URL", | ||
"type": "string", | ||
"required": false | ||
}, | ||
"attachmentSize": { | ||
"title": "Attachment Size (in bytes)", | ||
"type": "number", | ||
"required": false | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"attachmentToJson": { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,69 @@ | ||
/* eslint no-invalid-this: 0 no-console: 0 */ | ||
const eioUtils = require('elasticio-node').messages; | ||
const { AttachmentProcessor } = require('@elastic.io/component-commons-library'); | ||
const { messages } = require('elasticio-node'); | ||
const xml2js = require('xml2js'); | ||
const _ = require('lodash'); | ||
|
||
const ERROR = 'Prop name is invalid for XML tag'; | ||
const MB_TO_BYTES = 1024 * 1024; | ||
const MAX_FILE_SIZE = process.env.MAX_FILE_SIZE * MB_TO_BYTES || 10 * MB_TO_BYTES; | ||
|
||
/** | ||
* Checks whether property name is valid | ||
* @param {String} key - propName | ||
* @returns {Boolean} - valid prop or not | ||
*/ | ||
const propNameIsInvalid = (key) => /^\d/.test(key); | ||
module.exports.process = async function process(msg, cfg) { | ||
const { input } = msg.body; | ||
const { uploadToAttachment, excludeXmlHeader, headerStandalone } = cfg; | ||
|
||
/** | ||
* Checks whether object contains properties | ||
* that startsWith number | ||
* @see https://github.com/elasticio/xml-component/issues/1 | ||
* @param {Object|Number|String} value | ||
* @param {String} key | ||
*/ | ||
function validateJsonPropNames(value, key) { | ||
if (propNameIsInvalid(key)) { | ||
const message = 'Can\'t create XML element from prop that starts with digit.' | ||
+ 'See XML naming rules https://www.w3schools.com/xml/xml_elements.asp'; | ||
throw new Error(`${ERROR}: ${key}. ${message}`); | ||
} | ||
|
||
if (!_.isPlainObject(value)) { | ||
return; | ||
} | ||
this.logger.info('Message received.'); | ||
|
||
Object.keys(value).forEach((prop) => { | ||
validateJsonPropNames(value[prop], prop); | ||
}); | ||
} | ||
|
||
/** | ||
* This method will be called from elastic.io platform providing following data | ||
* | ||
* @param msg incoming message object that contains ``body`` with payload | ||
* @param cfg configuration that is account information and configuration field values | ||
*/ | ||
function processAction(msg, cfg) { | ||
this.logger.debug('Action started, message=%j cfg=%j', msg, cfg); | ||
const options = { | ||
trim: false, | ||
normalize: false, | ||
explicitArray: false, | ||
normalizeTags: false, | ||
attrkey: '_attr', | ||
tagNameProcessors: [ | ||
(name) => name.replace(':', '-'), | ||
], | ||
explicitRoot: false, | ||
xmldec: { | ||
standalone: headerStandalone, | ||
encoding: 'UTF-8', | ||
}, | ||
headless: excludeXmlHeader, | ||
}; | ||
const builder = new xml2js.Builder(options); | ||
|
||
const jsonToTransform = msg.body; | ||
// Check to make sure that input has at most one key | ||
// https://github.com/Leonidas-from-XIV/node-xml2js/issues/564 | ||
if (!_.isPlainObject(input) || Object.keys(input).length !== 1) { | ||
throw new Error('Input must be an object with exactly one key.'); | ||
} | ||
|
||
validateJsonPropNames(jsonToTransform); | ||
const xmlString = builder.buildObject(input); | ||
|
||
const result = builder.buildObject(jsonToTransform); | ||
this.logger.debug('Successfully converted body to XML result=%s', result); | ||
return eioUtils.newMessageWithBody({ | ||
xmlString: result, | ||
}); | ||
} | ||
if (!uploadToAttachment) { | ||
this.logger.info('Sending XML data in message.'); | ||
await this.emit('data', messages.newMessageWithBody({ | ||
xmlString, | ||
})); | ||
return; | ||
jhorbulyk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
const attachmentSize = Buffer.byteLength(xmlString); | ||
if (attachmentSize > MAX_FILE_SIZE) { | ||
throw new Error(`XML data is ${attachmentSize} bytes, and is too large to upload as an attachment. Max attachment size is ${MAX_FILE_SIZE} bytes`); | ||
} | ||
this.logger.info(`Will create XML attachment of size ${attachmentSize} byte(s)`); | ||
|
||
module.exports.process = processAction; | ||
const attachmentProcessor = new AttachmentProcessor(); | ||
const uploadResult = await attachmentProcessor.uploadAttachment(xmlString); | ||
const attachmentUrl = uploadResult.config.url; | ||
this.logger.info(`Successfully created attachment at ${attachmentUrl}`); | ||
|
||
const outboundMessage = messages.newEmptyMessage(); | ||
outboundMessage.attachments = { | ||
'jsonToXml.xml': { | ||
url: attachmentUrl, | ||
size: attachmentSize, | ||
}, | ||
}; | ||
outboundMessage.body = { | ||
attachmentUrl, | ||
attachmentSize, | ||
}; | ||
await this.emit('data', outboundMessage); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* eslint no-invalid-this: 0 no-console: 0 */ | ||
const eioUtils = require('elasticio-node').messages; | ||
const xml2js = require('xml2js'); | ||
const _ = require('lodash'); | ||
|
||
const ERROR = 'Prop name is invalid for XML tag'; | ||
|
||
/** | ||
* Checks whether property name is valid | ||
* @param {String} key - propName | ||
* @returns {Boolean} - valid prop or not | ||
*/ | ||
const propNameIsInvalid = (key) => /^\d/.test(key); | ||
|
||
/** | ||
* Checks whether object contains properties | ||
* that startsWith number | ||
* @see https://github.com/elasticio/xml-component/issues/1 | ||
* @param {Object|Number|String} value | ||
* @param {String} key | ||
*/ | ||
function validateJsonPropNames(value, key) { | ||
if (propNameIsInvalid(key)) { | ||
const message = 'Can\'t create XML element from prop that starts with digit.' | ||
+ 'See XML naming rules https://www.w3schools.com/xml/xml_elements.asp'; | ||
throw new Error(`${ERROR}: ${key}. ${message}`); | ||
} | ||
|
||
if (!_.isPlainObject(value)) { | ||
return; | ||
} | ||
|
||
Object.keys(value).forEach((prop) => { | ||
validateJsonPropNames(value[prop], prop); | ||
}); | ||
} | ||
|
||
/** | ||
* This method will be called from elastic.io platform providing following data | ||
* | ||
* @param msg incoming message object that contains ``body`` with payload | ||
* @param cfg configuration that is account information and configuration field values | ||
*/ | ||
function processAction(msg, cfg) { | ||
this.logger.debug('Action started, message=%j cfg=%j', msg, cfg); | ||
const options = { | ||
trim: false, | ||
normalize: false, | ||
explicitArray: false, | ||
normalizeTags: false, | ||
attrkey: '_attr', | ||
tagNameProcessors: [ | ||
(name) => name.replace(':', '-'), | ||
], | ||
}; | ||
const builder = new xml2js.Builder(options); | ||
|
||
const jsonToTransform = msg.body; | ||
|
||
validateJsonPropNames(jsonToTransform); | ||
|
||
const result = builder.buildObject(jsonToTransform); | ||
this.logger.debug('Successfully converted body to XML result=%s', result); | ||
return eioUtils.newMessageWithBody({ | ||
xmlString: result, | ||
}); | ||
} | ||
|
||
module.exports.process = processAction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So '_' or '#'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per the documentation
charKey
defaults to_
though it was#
in earlier versions. We can change it to whatever we want though...