diff --git a/.gitignore b/.gitignore
index 8428194c..6522e6f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.idea
.*.swp
node_modules/*
nyc_output/
diff --git a/README.md b/README.md
index afcd3f3d..5d55d816 100644
--- a/README.md
+++ b/README.md
@@ -92,15 +92,16 @@ Pass the following arguments to the parser function. All are optional.
`strict` - Boolean. Whether or not to be a jerk. Default: `false`.
-`opt` - Object bag of settings regarding string formatting. All default to `false`.
+`opt` - Object bag of settings regarding string formatting. All default to `false`, `looseCasing` default to `upper`.
Settings supported:
* `trim` - Boolean. Whether or not to trim text and comment nodes.
* `normalize` - Boolean. If true, then turn any whitespace into a single
space.
-* `lowercase` - Boolean. If true, then lowercase tag names and attribute names
- in loose mode, rather than uppercasing them.
+* `looseCasing` - String (`'lower'`/`'upper'`/`null`). In loose mode, the casing of tag names and
+ attributes will be lower/upper cased or unchanged.
+ The deprecated `lowercase` and `lowercasetags` overrides this property if set.
* `xmlns` - Boolean. If true, then namespaces are supported.
* `position` - Boolean. If false, then don't track line/col/position.
* `strictEntities` - Boolean. If true, only parse [predefined XML
@@ -174,8 +175,9 @@ but before any attributes are encountered. Argument: object with a
same object that will later be emitted in the `opentag` event.
`opentag` - An opening tag. Argument: object with `name` and `attributes`.
-In non-strict mode, tag names are uppercased, unless the `lowercase`
-option is set. If the `xmlns` option is set, then it will contain
+In non-strict mode, tag names will be lower/upper cased or unchanged if `looseCasing`
+option is set to `lower`, `upper` or `null` (defaults to `upper`).
+If the `xmlns` option is set, then it will contain
namespace binding information on the `ns` member, and will have a
`local`, `prefix`, and `uri` member.
@@ -185,8 +187,9 @@ self-closing tags will have `closeTag` emitted immediately after `openTag`.
Argument: tag name.
`attribute` - An attribute node. Argument: object with `name` and `value`.
-In non-strict mode, attribute names are uppercased, unless the `lowercase`
-option is set. If the `xmlns` option is set, it will also contains namespace
+In non-strict mode, attribute names will be lower/upper cased or unchanged if `looseCasing`
+option is set to `lower`, `upper` or `null` (defaults to `upper`).
+If the `xmlns` option is set, it will also contains namespace
information.
`comment` - A comment node. Argument: the string of the comment.
diff --git a/lib/sax.js b/lib/sax.js
index db0d4c31..0183fee1 100644
--- a/lib/sax.js
+++ b/lib/sax.js
@@ -42,6 +42,11 @@
'closenamespace'
]
+ var looseCaseMapping = {
+ lower: 'toLowerCase',
+ upper: 'toUpperCase'
+ }
+
function SAXParser (strict, opt) {
if (!(this instanceof SAXParser)) {
return new SAXParser(strict, opt)
@@ -52,8 +57,17 @@
parser.q = parser.c = ''
parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
parser.opt = opt || {}
- parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
- parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase'
+
+ if (!parser.opt.hasOwnProperty('looseCasing')) {
+ parser.opt.looseCasing = 'upper'
+ }
+ parser.looseCase = looseCaseMapping[parser.opt.looseCasing]
+
+ // backwards support for deprecated "lowercase" and "lowercasetags" options
+ if (parser.opt.hasOwnProperty('lowercase') || parser.opt.hasOwnProperty('lowercasetags')) {
+ parser.looseCase = (parser.opt.lowercase || parser.opt.lowercasetags) ? 'toLowerCase' : 'toUpperCase'
+ }
+
parser.tags = []
parser.closed = parser.closedRoot = parser.sawRoot = false
parser.tag = parser.error = null
@@ -695,7 +709,9 @@
}
function newTag (parser) {
- if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
+ if (!parser.strict && parser.looseCase) {
+ parser.tagName = parser.tagName[parser.looseCase]()
+ }
var parent = parser.tags[parser.tags.length - 1] || parser
var tag = parser.tag = { name: parser.tagName, attributes: {} }
@@ -723,7 +739,7 @@
}
function attrib (parser) {
- if (!parser.strict) {
+ if (!parser.strict && parser.looseCase) {
parser.attribName = parser.attribName[parser.looseCase]()
}
@@ -876,7 +892,7 @@
// will close everything, otherwise.
var t = parser.tags.length
var tagName = parser.tagName
- if (!parser.strict) {
+ if (!parser.strict && parser.looseCase) {
tagName = tagName[parser.looseCase]()
}
var closeTo = tagName
diff --git a/test/casing.js b/test/casing.js
new file mode 100644
index 00000000..223ed386
--- /dev/null
+++ b/test/casing.js
@@ -0,0 +1,125 @@
+// test lower looseCasing
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'span',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'class', value: 'test' } ],
+ [ 'attribute', { name: 'hello', value: 'world' } ],
+ [ 'opentag', {
+ name: 'span',
+ attributes: { class: 'test', hello: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'span' ]
+ ],
+ strict: false,
+ opt: {looseCasing: 'lower'}
+})
+
+// test upper looseCasing
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'SPAN',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'CLASS', value: 'test' } ],
+ [ 'attribute', { name: 'HELLO', value: 'world' } ],
+ [ 'opentag', {
+ name: 'SPAN',
+ attributes: { CLASS: 'test', HELLO: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'SPAN' ]
+ ],
+ strict: false,
+ opt: {looseCasing: 'upper'}
+})
+
+// test no looseCasing
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'span',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'className', value: 'test' } ],
+ [ 'attribute', { name: 'hello', value: 'world' } ],
+ [ 'opentag', {
+ name: 'span',
+ attributes: { className: 'test', hello: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'span' ]
+ ],
+ strict: false,
+ opt: {looseCasing: null}
+})
+
+// make sure deprecated lowercase overrides the looseCasing null option
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'span',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'classname', value: 'test' } ],
+ [ 'attribute', { name: 'hello', value: 'world' } ],
+ [ 'opentag', {
+ name: 'span',
+ attributes: { classname: 'test', hello: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'span' ]
+ ],
+ strict: false,
+ opt: {lowercase: true, looseCasing: null}
+})
+
+// make sure deprecated lowercase overrides the looseCasing upper option
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'span',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'classname', value: 'test' } ],
+ [ 'attribute', { name: 'hello', value: 'world' } ],
+ [ 'opentag', {
+ name: 'span',
+ attributes: { classname: 'test', hello: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'span' ]
+ ],
+ strict: false,
+ opt: {lowercase: true, looseCasing: 'upper'}
+})
+
+// make sure deprecated lowercasetags overrides the looseCasing upper option
+require(__dirname).test({
+ xml: '',
+ expect: [
+ [ 'opentagstart', {
+ name: 'span',
+ attributes: {}
+ } ],
+ [ 'attribute', { name: 'classname', value: 'test' } ],
+ [ 'attribute', { name: 'hello', value: 'world' } ],
+ [ 'opentag', {
+ name: 'span',
+ attributes: { classname: 'test', hello: 'world' },
+ isSelfClosing: false
+ } ],
+ [ 'closetag', 'span' ]
+ ],
+ strict: false,
+ opt: {lowercasetags: true, looseCasing: 'upper'}
+})