-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replaces XMLBuilder dependency with a light-weight implementation (#2045
) * Replaces XMLBuilder dependency with a light-weight implementation * Pins @types/node devDependency * Adds escaping apostrophes in XML attributes
- Loading branch information
1 parent
eef6e5c
commit b5df631
Showing
11 changed files
with
285 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"type": "feature", | ||
"category": "XML", | ||
"description": "Replaces XMLBuilder dependency with a light-weight XML builder." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** | ||
* Escapes characters that can not be in an XML attribute. | ||
*/ | ||
function escapeAttribute(value) { | ||
return value.replace(/&/g, '&').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); | ||
} | ||
|
||
/** | ||
* @api private | ||
*/ | ||
module.exports = { | ||
escapeAttribute: escapeAttribute | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** | ||
* Escapes characters that can not be in an XML element. | ||
*/ | ||
function escapeElement(value) { | ||
return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
} | ||
|
||
/** | ||
* @api private | ||
*/ | ||
module.exports = { | ||
escapeElement: escapeElement | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
var escapeAttribute = require('./escape-attribute').escapeAttribute; | ||
|
||
/** | ||
* Represents an XML node. | ||
* @api private | ||
*/ | ||
function XmlNode(name, children) { | ||
if (children === void 0) { children = []; } | ||
this.name = name; | ||
this.children = children; | ||
this.attributes = {}; | ||
} | ||
XmlNode.prototype.addAttribute = function (name, value) { | ||
this.attributes[name] = value; | ||
return this; | ||
}; | ||
XmlNode.prototype.addChildNode = function (child) { | ||
this.children.push(child); | ||
return this; | ||
}; | ||
XmlNode.prototype.removeAttribute = function (name) { | ||
delete this.attributes[name]; | ||
return this; | ||
}; | ||
XmlNode.prototype.toString = function () { | ||
var hasChildren = Boolean(this.children.length); | ||
var xmlText = '<' + this.name; | ||
// add attributes | ||
var attributes = this.attributes; | ||
for (var i = 0, attributeNames = Object.keys(attributes); i < attributeNames.length; i++) { | ||
var attributeName = attributeNames[i]; | ||
var attribute = attributes[attributeName]; | ||
if (typeof attribute !== 'undefined' && attribute !== null) { | ||
xmlText += ' ' + attributeName + '=\"' + escapeAttribute('' + attribute) + '\"'; | ||
} | ||
} | ||
return xmlText += !hasChildren ? '/>' : '>' + this.children.map(function (c) { return c.toString(); }).join('') + '</' + this.name + '>'; | ||
}; | ||
|
||
/** | ||
* @api private | ||
*/ | ||
module.exports = { | ||
XmlNode: XmlNode | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
var escapeElement = require('./escape-element').escapeElement; | ||
|
||
/** | ||
* Represents an XML text value. | ||
* @api private | ||
*/ | ||
function XmlText(value) { | ||
this.value = value; | ||
} | ||
|
||
XmlText.prototype.toString = function () { | ||
return escapeElement('' + this.value); | ||
}; | ||
|
||
/** | ||
* @api private | ||
*/ | ||
module.exports = { | ||
XmlText: XmlText | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
var escapeAttribute = require('../../lib/xml/escape-attribute').escapeAttribute; | ||
|
||
describe('escape-attribute', function() { | ||
it('escapes: & < > "\'', function() { | ||
var value = 'abc 123 &<>"%\''; | ||
expect(escapeAttribute(value)).to.equal('abc 123 &<>"%''); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
var escapeElement = require('../../lib/xml/escape-element').escapeElement; | ||
|
||
describe('escape-element', function() { | ||
it('escapes: & < >', function() { | ||
var value = 'abc 123 &<>"%'; | ||
expect(escapeElement(value)).to.equal('abc 123 &<>"%'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
var XmlNode = require('../../lib/xml/xml-node').XmlNode; | ||
var XmlText = require('../../lib/xml/xml-text').XmlText; | ||
|
||
describe('XmlNode', function() { | ||
it('creates empty xml documents', function() { | ||
var node = new XmlNode('Xml'); | ||
expect(node.toString()).to.equal('<Xml/>'); | ||
}); | ||
|
||
it('nests elements', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('element') | ||
]); | ||
expect(node.toString()).to.equal('<xml><element/></xml>'); | ||
}); | ||
|
||
it('nests elements deeply', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('a', [ | ||
new XmlNode('b', [ | ||
new XmlNode('c') | ||
]) | ||
]) | ||
]); | ||
expect(node.toString()).to.equal('<xml><a><b><c/></b></a></xml>'); | ||
}); | ||
|
||
it('supports flat elements with nested elements', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('a', [ | ||
new XmlNode('b') | ||
]), | ||
new XmlNode('c') | ||
]); | ||
expect(node.toString()).to.equal('<xml><a><b/></a><c/></xml>'); | ||
}); | ||
|
||
it('accepts element values', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('element', [ | ||
new XmlText('value') | ||
]) | ||
]); | ||
expect(node.toString()).to.equal('<xml><element>value</element></xml>'); | ||
}); | ||
|
||
it('accepts element attributes', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('el') | ||
.addAttribute('abc', 123) | ||
.addAttribute('mno', 'xyz') | ||
]); | ||
expect(node.toString()).to.equal('<xml><el abc="123" mno="xyz"/></xml>'); | ||
}); | ||
|
||
it('accepts element values and attributes at the same time', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('el', [ | ||
new XmlText('value') | ||
]).addAttribute('abc', 'xyz') | ||
]); | ||
expect(node.toString()).to.equal('<xml><el abc="xyz">value</el></xml>'); | ||
}); | ||
|
||
it('accepts attributes on outer elements', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('out', [ | ||
new XmlNode('c') | ||
]).addAttribute('a', 'b') | ||
]).addAttribute('xmlns', 'abc'); | ||
expect(node.toString()).to.equal('<xml xmlns="abc"><out a="b"><c/></out></xml>'); | ||
}); | ||
|
||
it('ignores null and undefined attributes', function() { | ||
var node = new XmlNode('xml'); | ||
expect(Object.keys(node.attributes).length).to.equal(0); | ||
node.addAttribute('foo', null); | ||
node.addAttribute('bar', undefined); | ||
node.addAttribute('baz', 123); | ||
node.addAttribute('bingo', 'bongo'); | ||
expect(node.toString()).to.equal('<xml baz="123" bingo="bongo"/>'); | ||
}); | ||
|
||
it('escapes attribute values and element text', function() { | ||
var node = new XmlNode('xml', [ | ||
new XmlNode('this & that') | ||
]).addAttribute('xmlns', 'a"b'); | ||
expect(node.toString()).to.equal('<xml xmlns="a"b"><this & that/></xml>'); | ||
}); | ||
|
||
describe('addAttribute', function() { | ||
it('adds an attribute to the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
expect(node.attributes['foo']).to.be.undefined; | ||
node.addAttribute('foo', 'bar'); | ||
expect(node.attributes['foo']).to.equal('bar'); | ||
}); | ||
|
||
it('returns a reference to the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
expect(node.addAttribute('foo', 'bar')).to.equal(node); | ||
}); | ||
}); | ||
|
||
describe('addChildNode', function() { | ||
it('adds a child to the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
expect(node.children.length === 0); | ||
node.addChildNode(new XmlNode('foo')); | ||
expect(node.children.length === 1); | ||
expect(node.toString()).to.equal('<xml><foo/></xml>'); | ||
}); | ||
|
||
it('returns a reference to the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
expect(node.addChildNode(new XmlNode('foo'))).to.equal(node); | ||
}); | ||
}); | ||
|
||
describe('removeAttribute', function() { | ||
it('removes an attribute from the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
node.addAttribute('foo', 'bar'); | ||
expect(node.attributes['foo']).to.equal('bar'); | ||
node.removeAttribute('foo'); | ||
expect(node.attributes['foo']).to.be.undefined; | ||
}); | ||
|
||
it('returns a reference to the XmlNode', function() { | ||
var node = new XmlNode('xml'); | ||
expect(node.removeAttribute('foo')).to.equal(node); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
var XmlText = require('../../lib/xml/xml-text').XmlText; | ||
|
||
describe('XmlText', function() { | ||
it('escapes element text', function() { | ||
var text = new XmlText('this & that are < or > "most"'); | ||
expect(text.toString()).to.equal('this & that are < or > "most"'); | ||
}); | ||
}); |