Skip to content

Conversation

@chrisradek
Copy link
Contributor

Adds an xml-builder package that contains just what our SDK needs to build XML documents. I tested this in the V2 SDK, and it passes all tests there as well.

/cc @jeskew

*/
export class XmlNode {

public attributes: {[name: string]: any} = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why leave this public? It seems like you would always want users of this class to manipulate the attributes via the adder and remover methods below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used public so tests wouldn't complain about ts compile errors, but I'll use the cast to any trick to get around it there.


public attributes: {[name: string]: any} = {};

constructor(public name: string, public children: XmlNode[] = []) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for these properties: why not make them private?


constructor(public name: string, public children: XmlNode[] = []) {}

escapeElement(value: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably also be private

return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

escapeAttribute(value: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto re: private

let xmlText = `<${this.name}`;
// add attributes
const attributes = this.attributes;
for (let attributeName in attributes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (let attributeName of Object.keys(attributes)) is more optimizable by V8 and will let you skip the has own property call on the next line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can change that.

I did find https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#5-for-in suggesting that v8 can better optimize for..of.

https://groups.google.com/forum/#!topic/v8-users/hHetuuOaSmw indicates that since hasOwnProperty is being used, the speed difference is negligible.Mileage may vary based on the engine being used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not really concerned with the performance difference... for ... of lets you skip the hasOwnProperty boilerplate.

xmlText += ` ${attributeName}="${this.escapeAttribute('' + attributes[attributeName])}"`;
}
// close the tag if there aren't any children
if (!hasChildren) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: you could write the rest of the function as single ternary expression.

/**
* Represents an XML text value.
*/
export class XmlText extends XmlNode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think inheritance is the right approach here, since XmlText instances will have inherited methods pertaining to children and attributes that will store data but not ultimately be used in the string output.

Maybe all you want to enforce is an interface with toString(): string defined? That would require escapeElement to be moved to a standalone function but would allow you to include anything other than null, undefined, or Object.create(null).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair, will update.

@chrisradek
Copy link
Contributor Author

Updated PR to address feedback.

} else {
xmlText += `>${this.children.map(c => c.toString()).join('')}</${this.name}>`;
for (let attributeName of Object.keys(attributes)) {
xmlText += ` ${attributeName}="${escapeAttribute('' + attributes[attributeName])}"`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: You might want to add a test ensuring that XmlNode can handle undefined and null attributes without throwing an error. I could see the '' + getting removed during a refactor, especially if doing so caused no test failures.

@chrisradek
Copy link
Contributor Author

I added a check so that undefined/null attributes will be ignored when XmlNode.toString() is called.

Copy link
Contributor

@jeskew jeskew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@chrisradek chrisradek merged commit 63f308d into master May 24, 2017
@chrisradek chrisradek deleted the xml-builder branch May 24, 2017 17:31
trivikr referenced this pull request in trivikr/aws-sdk-js-v3 Dec 10, 2018
@lock
Copy link

lock bot commented Sep 27, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@lock lock bot locked as resolved and limited conversation to collaborators Sep 27, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants