Skip to content

Commit 509f6d1

Browse files
committed
Added option for skipping null attribute values. Closes #26
1 parent b398ec5 commit 509f6d1

File tree

6 files changed

+92
-27
lines changed

6 files changed

+92
-27
lines changed

src/XMLBuilder.coffee

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ module.exports = class XMLBuilder
2323
#
2424
# `options.headless` whether XML declaration and doctype will be included: true or false
2525
# `options.allowSurrogateChars` whether surrogates will be allowed: true or false
26+
# `options.skipNullAttributes` whether attributes with null values will be ignored: true or false
2627
# `options.stringify` a set of functions to use for converting values to strings
2728
constructor: (name, options) ->
2829
if not name?
2930
throw new Error "Root element needs a name"
3031

3132
options ?= {}
33+
@options = options
3234
@stringify = new XMLStringifier options
3335

3436
temp = new XMLElement @, 'doc' # temporary node so that we can call element()
@@ -42,7 +44,7 @@ module.exports = class XMLBuilder
4244
root.declaration options
4345

4446
if options.pubID? or options.sysID?
45-
root.doctype options.pubID, options.sysID
47+
root.doctype options
4648

4749

4850
# Gets the root node

src/XMLElement.coffee

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module.exports = class XMLElement extends XMLNode
1515
# `attributes` an object containing name/value pairs of attributes
1616
constructor: (parent, name, attributes) ->
1717
super parent
18-
18+
1919
if not name?
2020
throw new Error "Missing element name"
2121

@@ -25,8 +25,7 @@ module.exports = class XMLElement extends XMLNode
2525

2626
@attributes = {}
2727
for own attName, attValue of attributes
28-
if attName? and attValue?
29-
@attributes[attName] = new XMLAttribute @, attName, attValue
28+
@attribute attName, attValue
3029

3130

3231
# Clones self
@@ -53,7 +52,7 @@ module.exports = class XMLElement extends XMLNode
5352
clonedChild = child.clone(deep)
5453
clonedChild.parent = clonedSelf
5554
clonedSelf.children.push clonedChild
56-
55+
5756
return clonedSelf
5857

5958

@@ -63,7 +62,8 @@ module.exports = class XMLElement extends XMLNode
6362
# `value` attribute value
6463
attribute: (name, value) ->
6564
value = value.apply() if _.isFunction value
66-
@attributes[name] = new XMLAttribute @, name, value
65+
if not @options.skipNullAttributes or value?
66+
@attributes[name] = new XMLAttribute @, name, value
6767
return @
6868

6969

src/XMLNode.coffee

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = class XMLNode
88
#
99
# `parent` the parent node
1010
constructor: (@parent) ->
11+
@options = @parent.options
1112
@stringify = @parent.stringify
1213

1314

src/index.coffee

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ XMLBuilder = require './XMLBuilder'
1515
#
1616
# `options.headless` whether XML declaration and doctype will be included: true or false
1717
# `options.allowSurrogateChars` whether surrogates will be allowed: true or false
18+
# `options.skipNullAttributes` whether attributes with null values will be ignored: true or false
1819
# `options.stringify` a set of functions to use for converting values to strings
1920
module.exports.create = (name, xmldec, doctype, options) ->
2021
options = _.extend { }, xmldec, doctype, options

test/attributes.coffee

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
vows = require 'vows'
2+
assert = require 'assert'
3+
4+
xmlbuilder = require '../src/index.coffee'
5+
6+
vows
7+
.describe('Editing')
8+
.addBatch
9+
'Add attribute':
10+
topic: () ->
11+
xmlbuilder.create('test4', { headless: true })
12+
.ele('node', 'element', {"first":"1", "second":"2"})
13+
.att("third", "3")
14+
15+
'resulting XML': (doc) ->
16+
xml = '<test4><node first="1" second="2" third="3">element</node></test4>'
17+
assert.strictEqual doc.end(), xml
18+
19+
'Remove attribute':
20+
topic: () ->
21+
root = xmlbuilder.create('test4', { headless: true })
22+
ele = root.ele('node', 'element', {"first":"1", "second":"2", "third":"3"})
23+
ele.removeAttribute("second")
24+
root
25+
26+
'resulting XML': (doc) ->
27+
xml = '<test4><node first="1" third="3">element</node></test4>'
28+
assert.strictEqual doc.end(), xml
29+
30+
'Throw if null attribute (ele)':
31+
topic: () ->
32+
xmlbuilder.create('test4', { headless: true })
33+
34+
'resulting XML': (root) ->
35+
assert.throws ->
36+
root.ele('node', 'element', {"first":null, "second":"2"})
37+
38+
'Throw if null attribute (att)':
39+
topic: () ->
40+
xmlbuilder.create('test4', { headless: true })
41+
42+
'resulting XML': (root) ->
43+
assert.throws ->
44+
root.ele('node').att("first")
45+
46+
'Throw if null attribute (JSON)':
47+
topic: () ->
48+
xmlbuilder.create('test4', { headless: true })
49+
50+
'resulting XML': (root) ->
51+
assert.throws ->
52+
root.ele({'@first': null})
53+
54+
'Skip if null attribute (ele)':
55+
topic: () ->
56+
xmlbuilder.create('test4', { headless: true, skipNullAttributes: true })
57+
.ele('node', 'element', {"first":null, 'second': '2'})
58+
59+
'resulting XML': (doc) ->
60+
xml = '<test4><node second="2">element</node></test4>'
61+
assert.strictEqual doc.end(), xml
62+
63+
'Skip if null attribute (att)':
64+
topic: () ->
65+
xmlbuilder.create('test4', { headless: true, skipNullAttributes: true })
66+
.ele('node').att("first")
67+
68+
'resulting XML': (doc) ->
69+
xml = '<test4><node/></test4>'
70+
assert.strictEqual doc.end(), xml
71+
72+
'Skip if null attribute (JSON)':
73+
topic: () ->
74+
xmlbuilder.create('test4', { headless: true, skipNullAttributes: true })
75+
.ele({'@first': null, '@second': '2'})
76+
77+
'resulting XML': (doc) ->
78+
xml = '<test4 second="2"/>'
79+
assert.strictEqual doc.end(), xml
80+
81+
.export(module)
82+

test/removeattribute.coffee

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)