diff --git a/README.md b/README.md
index c3278f7e..38925b20 100644
--- a/README.md
+++ b/README.md
@@ -282,6 +282,8 @@ value})``. Possible options are:
Version 0.1 default was `@`.
* `charkey` (default: `_`): Prefix that is used to access the character
content. Version 0.1 default was `#`.
+ * `commentskey` (default: `$comments`): Prefix that is used to access the comments.
+ * `parseComments` (default: `false`): Determines whether comments should be parsed.
* `explicitCharkey` (default: `false`)
* `trim` (default: `false`): Trim the whitespace at the beginning and end of
text nodes.
@@ -377,6 +379,7 @@ Possible options are:
Version 0.1 default was `@`.
* `charkey` (default: `_`): Prefix that is used to access the character
content. Version 0.1 default was `#`.
+ * `commentskey` (default: `$comments`): Prefix that is used to access the comments.
* `rootName` (default `root` or the root key name): root element name to be used in case
`explicitRoot` is `false` or to override the root element name.
* `renderOpts` (default `{ 'pretty': true, 'indent': ' ', 'newline': '\n' }`):
diff --git a/lib/builder.js b/lib/builder.js
index 58f36384..97f3f439 100644
--- a/lib/builder.js
+++ b/lib/builder.js
@@ -38,9 +38,10 @@
}
Builder.prototype.buildObject = function(rootObj) {
- var attrkey, charkey, render, rootElement, rootName;
+ var attrkey, charkey, commentskey, render, rootElement, rootName;
attrkey = this.options.attrkey;
charkey = this.options.charkey;
+ commentskey = this.options.commentskey;
if ((Object.keys(rootObj).length === 1) && (this.options.rootName === defaults['0.2'].rootName)) {
rootName = Object.keys(rootObj)[0];
rootObj = rootObj[rootName];
@@ -49,7 +50,7 @@
}
render = (function(_this) {
return function(element, obj) {
- var attr, child, entry, index, key, value;
+ var attr, child, entry, i, index, key, len, value;
if (typeof obj !== 'object') {
if (_this.options.cdata && requiresCDATA(obj)) {
element.raw(wrapCDATA(obj));
@@ -82,6 +83,11 @@
} else {
element = element.txt(child);
}
+ } else if (key === commentskey) {
+ for (i = 0, len = child.length; i < len; i++) {
+ value = child[i];
+ element = element.comment(value);
+ }
} else if (Array.isArray(child)) {
for (index in child) {
if (!hasProp.call(child, index)) continue;
diff --git a/lib/defaults.js b/lib/defaults.js
index 0a21da0a..abaeb9fa 100644
--- a/lib/defaults.js
+++ b/lib/defaults.js
@@ -33,6 +33,8 @@
normalizeTags: false,
attrkey: "$",
charkey: "_",
+ commentskey: "$comments",
+ parseComments: false,
explicitArray: true,
ignoreAttrs: false,
mergeAttrs: false,
diff --git a/lib/parser.js b/lib/parser.js
index 9e8261eb..720698bf 100644
--- a/lib/parser.js
+++ b/lib/parser.js
@@ -106,7 +106,7 @@
};
Parser.prototype.reset = function() {
- var attrkey, charkey, ontext, stack;
+ var attrkey, charkey, commentskey, ontext, stack;
this.removeAllListeners();
this.saxParser = sax.parser(this.options.strict, {
trim: false,
@@ -137,6 +137,7 @@
stack = [];
attrkey = this.options.attrkey;
charkey = this.options.charkey;
+ commentskey = this.options.commentskey;
this.saxParser.onopentag = (function(_this) {
return function(node) {
var key, newValue, obj, processedKey, ref;
@@ -284,7 +285,7 @@
};
})(this);
this.saxParser.ontext = ontext;
- return this.saxParser.oncdata = (function(_this) {
+ this.saxParser.oncdata = (function(_this) {
return function(text) {
var s;
s = ontext(text);
@@ -293,6 +294,19 @@
}
};
})(this);
+ if (this.options.parseComments) {
+ return this.saxParser.oncomment = (function(_this) {
+ return function(text) {
+ var s;
+ s = stack[stack.length - 1];
+ if (s) {
+ s[commentskey] = s[commentskey] || [];
+ s[commentskey].push(text.slice(1, -1));
+ return s;
+ }
+ };
+ })(this);
+ }
};
Parser.prototype.parseString = function(str, cb) {
diff --git a/src/builder.coffee b/src/builder.coffee
index 5653fde0..207f05ca 100644
--- a/src/builder.coffee
+++ b/src/builder.coffee
@@ -30,6 +30,7 @@ class exports.Builder
buildObject: (rootObj) ->
attrkey = @options.attrkey
charkey = @options.charkey
+ commentskey = @options.commentskey
# If there is a sane-looking first element to use as the root,
# and the user hasn't specified a non-default rootName,
@@ -69,7 +70,12 @@ class exports.Builder
else
element = element.txt child
- # Case #3 Array data
+ # Case #3 Comment
+ else if key is commentskey
+ for value in child
+ element = element.comment value
+
+ # Case #4 Array data
else if Array.isArray child
for own index, entry of child
if typeof entry is 'string'
@@ -80,11 +86,11 @@ class exports.Builder
else
element = render(element.ele(key), entry).up()
- # Case #4 Objects
+ # Case #5 Objects
else if typeof child is "object"
element = render(element.ele(key), child).up()
- # Case #5 String and remaining types
+ # Case #6 String and remaining types
else
if typeof child is 'string' && @options.cdata && requiresCDATA child
element = element.ele(key).raw(wrapCDATA child).up()
diff --git a/src/defaults.coffee b/src/defaults.coffee
index a9bd214b..49e35fd9 100644
--- a/src/defaults.coffee
+++ b/src/defaults.coffee
@@ -42,6 +42,8 @@ exports.defaults = {
normalizeTags: false
attrkey: "$"
charkey: "_"
+ commentskey: "$comments"
+ parseComments: false
explicitArray: true
ignoreAttrs: false
mergeAttrs: false
diff --git a/src/parser.coffee b/src/parser.coffee
index 8a375197..f4cc31c3 100644
--- a/src/parser.coffee
+++ b/src/parser.coffee
@@ -100,6 +100,7 @@ class exports.Parser extends events.EventEmitter
# aliases, so we don't have to type so much
attrkey = @options.attrkey
charkey = @options.charkey
+ commentskey = @options.commentskey
@saxParser.onopentag = (node) =>
obj = {}
@@ -225,6 +226,14 @@ class exports.Parser extends events.EventEmitter
if s
s.cdata = true
+ if @options.parseComments
+ @saxParser.oncomment = (text) =>
+ s = stack[stack.length - 1]
+ if s
+ s[commentskey] = s[commentskey] or []
+ s[commentskey].push text.slice(1,-1)
+ s
+
parseString: (str, cb) =>
if cb? and typeof cb is "function"
@on "end", (result) ->
diff --git a/test/builder.test.coffee b/test/builder.test.coffee
index e9c12be3..5523dc89 100644
--- a/test/builder.test.coffee
+++ b/test/builder.test.coffee
@@ -137,7 +137,7 @@ module.exports =
fileName = path.join __dirname, '/fixtures/build_sample.xml'
fs.readFile fileName, (err, xmlData) ->
xmlExpected = xmlData.toString()
- xml2js.parseString xmlData, {'trim': true}, (err, obj) ->
+ xml2js.parseString xmlData, {'trim': true, 'parseComments': true}, (err, obj) ->
equ err, null
builder = new xml2js.Builder({})
xmlActual = builder.buildObject obj
diff --git a/test/fixtures/build_sample.xml b/test/fixtures/build_sample.xml
index 494a1b18..4e5a8733 100644
--- a/test/fixtures/build_sample.xml
+++ b/test/fixtures/build_sample.xml
@@ -3,7 +3,9 @@
Character data here!
+
+
-
This is
character
diff --git a/test/fixtures/sample.xml b/test/fixtures/sample.xml
index 0ffea408..41caf2dd 100644
--- a/test/fixtures/sample.xml
+++ b/test/fixtures/sample.xml
@@ -4,11 +4,13 @@
+
Line One
Line Two
+
-
This Foo(1) is
Foo(2)
diff --git a/test/parser.test.coffee b/test/parser.test.coffee
index 6d531d56..c5075474 100644
--- a/test/parser.test.coffee
+++ b/test/parser.test.coffee
@@ -72,6 +72,11 @@ module.exports =
# determine number of items in object
equ Object.keys(r.sample.tagcasetest[0]).length, 3)
+ 'test parse with parseComments': skeleton(parseComments: true, (r) ->
+ console.log 'Result object: ' + util.inspect r, false, 10
+ equ r.sample.$comments[0], 'This is the first sample comment!'
+ equ r.sample.listtest[0].$comments[0], 'This is the second sample comment!')
+
'test parse with explicitCharkey': skeleton(explicitCharkey: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
equ r.sample.chartest[0].$.desc, 'Test for CHARs'
@@ -190,32 +195,32 @@ module.exports =
'test parse with explicitChildren and charsAsChildren and preserveChildrenOrder and includeWhiteChars': skeleton(explicitChildren: true, preserveChildrenOrder: true, charsAsChildren: true, includeWhiteChars: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
- equ r.sample.$$[35]['#name'], 'textordertest'
- equ r.sample.$$[35].$$[0]['#name'], '__text__'
- equ r.sample.$$[35].$$[0]._, 'this is text with '
- equ r.sample.$$[35].$$[1]['#name'], 'b'
- equ r.sample.$$[35].$$[1]._, 'markup'
- equ r.sample.$$[35].$$[2]['#name'], '__text__'
- equ r.sample.$$[35].$$[2]._, ' '
- equ r.sample.$$[35].$$[3]['#name'], 'em'
- equ r.sample.$$[35].$$[3]._, 'like this'
- equ r.sample.$$[35].$$[4]['#name'], '__text__'
- equ r.sample.$$[35].$$[4]._, ' in the middle')
+ equ r.sample.$$[36]['#name'], 'textordertest'
+ equ r.sample.$$[36].$$[0]['#name'], '__text__'
+ equ r.sample.$$[36].$$[0]._, 'this is text with '
+ equ r.sample.$$[36].$$[1]['#name'], 'b'
+ equ r.sample.$$[36].$$[1]._, 'markup'
+ equ r.sample.$$[36].$$[2]['#name'], '__text__'
+ equ r.sample.$$[36].$$[2]._, ' '
+ equ r.sample.$$[36].$$[3]['#name'], 'em'
+ equ r.sample.$$[36].$$[3]._, 'like this'
+ equ r.sample.$$[36].$$[4]['#name'], '__text__'
+ equ r.sample.$$[36].$$[4]._, ' in the middle')
'test parse with explicitChildren and charsAsChildren and preserveChildrenOrder and includeWhiteChars and normalize': skeleton(explicitChildren: true, preserveChildrenOrder: true, charsAsChildren: true, includeWhiteChars: true, normalize: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
# normalized whitespace-only text node becomes empty string
- equ r.sample.$$[35]['#name'], 'textordertest'
- equ r.sample.$$[35].$$[0]['#name'], '__text__'
- equ r.sample.$$[35].$$[0]._, 'this is text with'
- equ r.sample.$$[35].$$[1]['#name'], 'b'
- equ r.sample.$$[35].$$[1]._, 'markup'
- equ r.sample.$$[35].$$[2]['#name'], '__text__'
- equ r.sample.$$[35].$$[2]._, ''
- equ r.sample.$$[35].$$[3]['#name'], 'em'
- equ r.sample.$$[35].$$[3]._, 'like this'
- equ r.sample.$$[35].$$[4]['#name'], '__text__'
- equ r.sample.$$[35].$$[4]._, 'in the middle')
+ equ r.sample.$$[36]['#name'], 'textordertest'
+ equ r.sample.$$[36].$$[0]['#name'], '__text__'
+ equ r.sample.$$[36].$$[0]._, 'this is text with'
+ equ r.sample.$$[36].$$[1]['#name'], 'b'
+ equ r.sample.$$[36].$$[1]._, 'markup'
+ equ r.sample.$$[36].$$[2]['#name'], '__text__'
+ equ r.sample.$$[36].$$[2]._, ''
+ equ r.sample.$$[36].$$[3]['#name'], 'em'
+ equ r.sample.$$[36].$$[3]._, 'like this'
+ equ r.sample.$$[36].$$[4]['#name'], '__text__'
+ equ r.sample.$$[36].$$[4]._, 'in the middle')
'test element without children': skeleton(explicitChildren: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10