├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── lib └── xml-writer.js ├── package.json └── test ├── attributes.js ├── cdata.js ├── comments.js ├── doctype.js ├── document.js ├── element.js ├── misc.js ├── namespaces.js ├── pi.js ├── raw.js └── writer.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz 2 | *.swp 3 | *.swo 4 | README.html 5 | *.sw? 6 | coverage/ 7 | node_modules/ 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | *.sw? 3 | coverage 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - 0.10 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 Nicolas Thouvenin 2 | 3 | This project is free software released under the MIT/X11 license: 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XMLWriter for NodeJS 2 | 3 | [![Build Status](https://secure.travis-ci.org/touv/node-xml-writer.png?branch=master)](http://travis-ci.org/touv/node-xml-writer) 4 | 5 | It's native and full javascript implementation of the classic XMLWriter class. 6 | The API is complete, flexible and tolerant. 7 | XML is still valid. 8 | 9 | ## Contributors 10 | 11 | * [Nicolas Thouvenin](https://github.com/touv) 12 | * [Anton Zem](https://github.com/AlgoTrader) 13 | * [Chip Lee](https://github.com/chipincode) 14 | * [Peecky](https://github.com/peecky) 15 | * [Julian Scheid](https://github.com/jscheid) 16 | * [Guillaume Plique](https://github.com/Yomguithereal) 17 | 18 | # Installation 19 | 20 | With [npm](http://npmjs.org) do: 21 | 22 | $ npm install xml-writer 23 | 24 | 25 | # Examples 26 | 27 | ## Basic 28 | ```javascript 29 | var XMLWriter = require('xml-writer'); 30 | xw = new XMLWriter; 31 | xw.startDocument(); 32 | xw.startElement('root'); 33 | xw.writeAttribute('foo', 'value'); 34 | xw.text('Some content'); 35 | xw.endDocument(); 36 | 37 | console.log(xw.toString()); 38 | ``` 39 | Output: 40 | 41 | 42 | Some content 43 | 44 | Tip: If you want your XML **indented** use `new XMLWriter(true)` or `new XMLWriter('\t')`, for instance, if you want to use a custom string for indentation. 45 | 46 | ## Chaining 47 | ```javascript 48 | var XMLWriter = require('xml-writer'); 49 | xw = new XMLWriter; 50 | xw.startDocument().startElement('root').writeAttribute('foo', 'value').writeElement('tag', 'Some content'); 51 | 52 | console.log(xw.toString()); 53 | ``` 54 | Output: 55 | 56 | 57 | Some content 58 | 59 | ## Tolerant 60 | ```javascript 61 | var XMLWriter = require('xml-writer'); 62 | xw = new XMLWriter; 63 | xw.startElement('root').writeAttribute('foo', 'value').text('Some content'); 64 | 65 | console.log(xw.toString()); 66 | ``` 67 | Output: 68 | 69 | Some content 70 | 71 | 72 | ## Extensible 73 | ```javascript 74 | var XMLWriter = require('xml-writer'), 75 | fs = require('fs'); 76 | var ws = fs.createWriteStream('/tmp/foo.xml'); 77 | ws.on('close', function() { 78 | console.log(fs.readFileSync('/tmp/foo.xml', 'UTF-8')); 79 | }); 80 | xw = new XMLWriter(false, function(string, encoding) { 81 | ws.write(string, encoding); 82 | }); 83 | xw.startDocument('1.0', 'UTF-8').startElement(function() { 84 | return 'root'; 85 | }).text(function() { 86 | return 'Some content'; 87 | }); 88 | ws.end(); 89 | ``` 90 | 91 | Output: 92 | 93 | 94 | Some content 95 | 96 | 97 | # Tests 98 | 99 | Use [nodeunit](https://github.com/caolan/nodeunit) to run the tests. 100 | 101 | $ npm install nodeunit 102 | $ nodeunit test 103 | 104 | # API Documentation 105 | 106 | ## Generic 107 | 108 | ### constructor XMLWriter(Boolean|String indent, Function writer(string, encoding)) 109 | Create an new writer 110 | 111 | ### text(String content) 112 | Write text 113 | 114 | ### writeRaw 115 | Write a raw XML text 116 | 117 | ## Document 118 | ### startDocument(String version = '1.0', String encoding = NULL, Boolean standalone = false) 119 | Create document tag 120 | 121 | ### endDocument() 122 | End current document 123 | 124 | ## Element 125 | 126 | ### writeElement(String name, String content) 127 | Write full element tag 128 | 129 | ### writeElementNS 130 | Write full namespaced element tag 131 | 132 | ### startElementNS 133 | Create start namespaced element tag 134 | 135 | ### startElement(String name) 136 | Create start element tag 137 | 138 | ### endElement() 139 | End current element 140 | 141 | ## Attributes 142 | 143 | ### writeAttribute(String name, String value) 144 | Write full attribute 145 | 146 | ### writeAttributeNS 147 | Write full namespaced attribute 148 | 149 | ### startAttributeNS 150 | Create start namespaced attribute 151 | 152 | ### startAttribute(String name) 153 | Create start attribute 154 | 155 | ### endAttribute() 156 | End attribute 157 | 158 | ## Processing Instruction 159 | 160 | ### writePI(String name, String content) 161 | Writes a PI 162 | 163 | ### startPI(String name) 164 | Create start PI tag 165 | 166 | ### endPI() 167 | End current PI 168 | 169 | ## DocType 170 | 171 | ### writeDocType(String name, String pubid, String sysid, String subset) 172 | Write a DocType 173 | 174 | ### startDocType(String name, String pubid, String sysid, String subset) 175 | Create start DocType tag 176 | 177 | ### endDocType() 178 | End current DocType 179 | 180 | ## CData 181 | 182 | ### writeCData(String content) 183 | Write full CDATA tag 184 | 185 | ### startCData() 186 | Create start CDATA tag 187 | 188 | ### endCData() 189 | End current CDATA 190 | 191 | ## Comment 192 | 193 | ### writeComment(String content) 194 | Write full comment tag 195 | 196 | ### startComment() 197 | Create start comment 198 | 199 | ### endComment() 200 | Create end comment 201 | 202 | # Also 203 | 204 | * https://github.com/minchenkov/simple-xml-writer 205 | * https://github.com/wezm/node-genx 206 | 207 | # License 208 | 209 | [MIT/X11](./LICENSE) 210 | 211 | 212 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/touv/node-xml-writer/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 213 | 214 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/xml-writer.js'); 2 | -------------------------------------------------------------------------------- /lib/xml-writer.js: -------------------------------------------------------------------------------- 1 | 2 | function isFalse(s) { 3 | return typeof s !== 'number' && !s; 4 | } 5 | 6 | function strval(s) { 7 | if (typeof s == 'string') { 8 | return s; 9 | } 10 | else if (typeof s == 'number') { 11 | return s+''; 12 | } 13 | else if (typeof s == 'function') { 14 | return s(); 15 | } 16 | else if (s instanceof XMLWriter) { 17 | return s.toString(); 18 | } 19 | else throw Error('Bad Parameter'); 20 | } 21 | 22 | function XMLWriter(indent, callback) { 23 | 24 | if (!(this instanceof XMLWriter)) { 25 | return new XMLWriter(); 26 | } 27 | 28 | this.name_regex = /[_:A-Za-z][-._:A-Za-z0-9]*/; 29 | this.indent = indent ? true : false; 30 | this.indentString = this.indent && typeof indent === 'string' ? indent : ' '; 31 | this.output = ''; 32 | this.stack = []; 33 | this.tags = 0; 34 | this.attributes = 0; 35 | this.attribute = 0; 36 | this.texts = 0; 37 | this.comment = 0; 38 | this.dtd = 0; 39 | this.root = ''; 40 | this.pi = 0; 41 | this.cdata = 0; 42 | this.started_write = false; 43 | this.writer; 44 | this.writer_encoding = 'UTF-8'; 45 | 46 | if (typeof callback == 'function') { 47 | this.writer = callback; 48 | } else { 49 | this.writer = function (s, e) { 50 | this.output += s; 51 | } 52 | } 53 | } 54 | 55 | XMLWriter.prototype = { 56 | toString : function () { 57 | this.flush(); 58 | return this.output; 59 | }, 60 | 61 | indenter : function () { 62 | if (this.indent) { 63 | this.write('\n'); 64 | for (var i = 1; i < this.tags; i++) { 65 | this.write(this.indentString); 66 | } 67 | } 68 | }, 69 | 70 | write : function () { 71 | for (var i = 0; i < arguments.length; i++) { 72 | this.writer(arguments[i], this.writer_encoding); 73 | } 74 | }, 75 | 76 | 77 | flush : function () { 78 | for (var i = this.tags; i > 0; i--) { 79 | this.endElement(); 80 | } 81 | this.tags = 0; 82 | }, 83 | 84 | startDocument : function (version, encoding, standalone) { 85 | if (this.tags || this.attributes) return this; 86 | 87 | this.startPI('xml'); 88 | this.startAttribute('version'); 89 | this.text(typeof version == "string" ? version : "1.0"); 90 | this.endAttribute(); 91 | if (typeof encoding == "string") { 92 | this.startAttribute('encoding'); 93 | this.text(encoding); 94 | this.endAttribute(); 95 | this.writer_encoding = encoding; 96 | } 97 | if (standalone) { 98 | this.startAttribute('standalone'); 99 | this.text("yes"); 100 | this.endAttribute(); 101 | } 102 | this.endPI(); 103 | if (!this.indent) { 104 | this.write('\n'); 105 | } 106 | return this; 107 | }, 108 | 109 | endDocument : function () { 110 | if (this.attributes) this.endAttributes(); 111 | return this; 112 | }, 113 | 114 | writeElement : function (name, content) { 115 | return this.startElement(name).text(content).endElement(); 116 | }, 117 | 118 | writeElementNS : function (prefix, name, uri, content) { 119 | if (!content) { 120 | content = uri; 121 | } 122 | return this.startElementNS(prefix, name, uri).text(content).endElement(); 123 | }, 124 | 125 | startElement : function (name) { 126 | name = strval(name); 127 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 128 | if (this.tags === 0 && this.root && this.root !== name) throw Error('Invalid Parameter'); 129 | if (this.attributes) this.endAttributes(); 130 | ++this.tags; 131 | this.texts = 0; 132 | if (this.stack.length > 0) 133 | this.stack[this.stack.length-1].containsTag = true; 134 | 135 | this.stack.push({ 136 | name: name, 137 | tags: this.tags 138 | }); 139 | if (this.started_write) this.indenter(); 140 | this.write('<', name); 141 | this.startAttributes(); 142 | this.started_write = true; 143 | return this; 144 | }, 145 | startElementNS : function (prefix, name, uri) { 146 | prefix = strval(prefix); 147 | name = strval(name); 148 | 149 | if (!prefix.match(this.name_regex)) throw Error('Invalid Parameter'); 150 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 151 | if (this.attributes) this.endAttributes(); 152 | ++this.tags; 153 | this.texts = 0; 154 | if (this.stack.length > 0) 155 | this.stack[this.stack.length-1].containsTag = true; 156 | 157 | this.stack.push({ 158 | name: prefix + ':' + name, 159 | tags: this.tags 160 | }); 161 | if (this.started_write) this.indenter(); 162 | this.write('<', prefix + ':' + name); 163 | this.startAttributes(); 164 | this.started_write = true; 165 | return this; 166 | }, 167 | 168 | endElement : function () { 169 | if (!this.tags) return this; 170 | var t = this.stack.pop(); 171 | if (this.attributes > 0) { 172 | if (this.attribute) { 173 | if (this.texts) this.endAttribute(); 174 | this.endAttribute(); 175 | } 176 | this.write('/'); 177 | this.endAttributes(); 178 | } else { 179 | if (t.containsTag) this.indenter(); 180 | this.write(''); 181 | } 182 | --this.tags; 183 | this.texts = 0; 184 | return this; 185 | }, 186 | 187 | writeAttribute : function (name, content) { 188 | if (typeof content == 'function') { 189 | content = content(); 190 | } 191 | if (isFalse(content)) { 192 | return this; 193 | } 194 | return this.startAttribute(name).text(content).endAttribute(); 195 | }, 196 | writeAttributeNS : function (prefix, name, uri, content) { 197 | if (!content) { 198 | content = uri; 199 | } 200 | if (typeof content == 'function') { 201 | content = content(); 202 | } 203 | if (isFalse(content)) { 204 | return this; 205 | } 206 | return this.startAttributeNS(prefix, name, uri).text(content).endAttribute(); 207 | }, 208 | 209 | startAttributes : function () { 210 | this.attributes = 1; 211 | return this; 212 | }, 213 | 214 | endAttributes : function () { 215 | if (!this.attributes) return this; 216 | if (this.attribute) this.endAttribute(); 217 | this.attributes = 0; 218 | this.attribute = 0; 219 | this.texts = 0; 220 | this.write('>'); 221 | return this; 222 | }, 223 | 224 | startAttribute : function (name) { 225 | name = strval(name); 226 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 227 | if (!this.attributes && !this.pi) return this; 228 | if (this.attribute) return this; 229 | this.attribute = 1; 230 | this.write(' ', name, '="'); 231 | return this; 232 | }, 233 | startAttributeNS : function (prefix, name, uri) { 234 | prefix = strval(prefix); 235 | name = strval(name); 236 | 237 | if (!prefix.match(this.name_regex)) throw Error('Invalid Parameter'); 238 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 239 | if (!this.attributes && !this.pi) return this; 240 | if (this.attribute) return this; 241 | this.attribute = 1; 242 | this.write(' ', prefix + ':' + name, '="'); 243 | return this; 244 | }, 245 | endAttribute : function () { 246 | if (!this.attribute) return this; 247 | this.attribute = 0; 248 | this.texts = 0; 249 | this.write('"'); 250 | return this; 251 | }, 252 | 253 | text : function (content) { 254 | content = strval(content); 255 | if (!this.tags && !this.comment && !this.pi && !this.cdata) return this; 256 | if (this.attributes && this.attribute) { 257 | ++this.texts; 258 | this.write(content 259 | .replace(/&/g, '&') 260 | .replace(//g, '>')); 275 | } 276 | ++this.texts; 277 | this.started_write = true; 278 | return this; 279 | }, 280 | 281 | writeComment : function (content) { 282 | return this.startComment().text(content).endComment(); 283 | }, 284 | 285 | startComment : function () { 286 | if (this.comment) return this; 287 | if (this.attributes) this.endAttributes(); 288 | this.indenter(); 289 | this.write(''); 298 | this.comment = 0; 299 | return this; 300 | }, 301 | 302 | writeDocType : function (name, pubid, sysid, subset) { 303 | return this.startDocType(name, pubid, sysid, subset).endDocType() 304 | }, 305 | 306 | startDocType : function (name, pubid, sysid, subset) { 307 | if (this.dtd || this.tags) return this; 308 | 309 | name = strval(name); 310 | pubid = pubid ? strval(pubid) : pubid; 311 | sysid = sysid ? strval(sysid) : sysid; 312 | subset = subset ? strval(subset) : subset; 313 | 314 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 315 | if (pubid && !pubid.match(/^[\w\-][\w\s\-\/\+\:\.]*/)) throw Error('Invalid Parameter'); 316 | if (sysid && !sysid.match(/^[\w\.][\w\-\/\\\:\.]*/)) throw Error('Invalid Parameter'); 317 | if (subset && !subset.match(/[\w\s\<\>\+\.\!\#\-\?\*\,\(\)\|]*/)) throw Error('Invalid Parameter'); 318 | 319 | pubid = pubid ? ' PUBLIC "' + pubid + '"' : (sysid) ? ' SYSTEM' : ''; 320 | sysid = sysid ? ' "' + sysid + '"' : ''; 321 | subset = subset ? ' [' + subset + ']': ''; 322 | 323 | if (this.started_write) this.indenter(); 324 | this.write(''); 334 | return this; 335 | }, 336 | 337 | writePI : function (name, content) { 338 | return this.startPI(name).text(content).endPI() 339 | }, 340 | 341 | startPI : function (name) { 342 | name = strval(name); 343 | if (!name.match(this.name_regex)) throw Error('Invalid Parameter'); 344 | if (this.pi) return this; 345 | if (this.attributes) this.endAttributes(); 346 | if (this.started_write) this.indenter(); 347 | this.write(''); 356 | this.pi = 0; 357 | return this; 358 | }, 359 | 360 | writeCData : function (content) { 361 | return this.startCData().text(content).endCData(); 362 | }, 363 | 364 | startCData : function () { 365 | if (this.cdata) return this; 366 | if (this.attributes) this.endAttributes(); 367 | this.indenter(); 368 | this.write(''); 377 | this.cdata = 0; 378 | return this; 379 | }, 380 | 381 | writeRaw : function(content) { 382 | content = strval(content); 383 | if (!this.tags && !this.comment && !this.pi && !this.cdata) return this; 384 | if (this.attributes && this.attribute) { 385 | ++this.texts; 386 | this.write(content.replace('&', '&').replace('"', '"')); 387 | return this; 388 | } else if (this.attributes && !this.attribute) { 389 | this.endAttributes(); 390 | } 391 | ++this.texts; 392 | this.write(content); 393 | this.started_write = true; 394 | return this; 395 | } 396 | 397 | } 398 | 399 | module.exports = XMLWriter; 400 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xml-writer", 3 | "version": "1.7.0", 4 | "author": "Nicolas Thouvenin ", 5 | "contributors": [ 6 | { 7 | "name": "Anton Zem" 8 | }, 9 | { 10 | "name": "Chip Lee", 11 | "url": "https://github.com/chipincode" 12 | }, 13 | { 14 | "name": "Peecky", 15 | "url": "https://github.com/peecky" 16 | }, 17 | { 18 | "name": "Julian Scheid", 19 | "url": "https://github.com/jscheid" 20 | } 21 | ], 22 | "description": "Native and full Javascript implementation of the classic XMLWriter class", 23 | "keywords": [ 24 | "xml", 25 | "writer", 26 | "XMLWriter", 27 | "generator" 28 | ], 29 | "homepage": "http://github.com/touv/node-xml-writer", 30 | "scripts": { 31 | "truc": "nodeunit test/", 32 | "test": "./node_modules/.bin/istanbul test ./node_modules/.bin/nodeunit test/" 33 | }, 34 | "main": "./index.js", 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/touv/node-xml-writer.git" 38 | }, 39 | "dependencies": {}, 40 | "devDependencies": { 41 | "nodeunit": ">=0.7.3", 42 | "istanbul": "*" 43 | }, 44 | "license": "MIT", 45 | "engines": { 46 | "node": ">=0.4.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/attributes.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter; 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.startAttribute('key'); 8 | this.xw.text('value'); 9 | this.xw.endAttribute(); 10 | test.equal(this.xw.toString(), ''); 11 | test.done(); 12 | }; 13 | exports['t02'] = function (test) { 14 | this.xw.startElement('tag'); 15 | this.xw.startAttribute('key'); 16 | this.xw.text('value'); 17 | this.xw.endAttribute(); 18 | test.equal(this.xw.toString(), ''); 19 | test.done(); 20 | }; 21 | exports['t03'] = function (test) { 22 | this.xw.startElement('tag'); 23 | this.xw.startAttribute('key1'); 24 | this.xw.text('value'); 25 | this.xw.endAttribute(); 26 | this.xw.startAttribute('key2'); 27 | this.xw.text('value'); 28 | this.xw.endAttribute(); 29 | test.equal(this.xw.toString(), ''); 30 | test.done(); 31 | }; 32 | exports['t04'] = function (test) { 33 | this.xw.startElement('tag'); 34 | this.xw.startAttribute('key1'); 35 | this.xw.startAttribute('key2'); 36 | this.xw.text('value'); 37 | this.xw.endAttribute(); 38 | test.equal(this.xw.toString(), ''); 39 | test.done(); 40 | }; 41 | exports['t05'] = function (test) { 42 | this.xw.startElement('tag'); 43 | this.xw.startAttribute('key1'); 44 | this.xw.startElement('tag'); 45 | this.xw.text('value'); 46 | test.equal(this.xw.toString(), 'value'); 47 | test.done(); 48 | }; 49 | exports['t06a'] = function (test) { 50 | this.xw.startElement('tag').writeAttribute('key', 'value').endElement(); 51 | test.equal(this.xw.toString(), ''); 52 | test.done(); 53 | }; 54 | exports['t06b'] = function (test) { 55 | this.xw.startElement('tag').writeAttribute('key', '"< & >"').endElement(); 56 | test.equal(this.xw.toString(), ''); 57 | test.done(); 58 | }; 59 | exports['t07'] = function (test) { 60 | this.xw.startElement('tag'); 61 | this.xw.writeAttribute('key1', false); 62 | this.xw.writeAttribute('key2', null); 63 | this.xw.writeAttribute('key3', undefined); 64 | test.equal(this.xw.toString(), ''); 65 | test.done(); 66 | }; 67 | exports['t08'] = function (test) { 68 | this.xw.startElement('tag'); 69 | this.xw.writeAttribute('key1', '\t\n\r'); 70 | test.equal(this.xw.toString(), ''); 71 | test.done(); 72 | }; 73 | -------------------------------------------------------------------------------- /test/cdata.js: -------------------------------------------------------------------------------- 1 | 2 | var XMLWriter = require('../'); 3 | exports['setUp'] = function (callback) { 4 | this.xw = new XMLWriter; 5 | callback(); 6 | }; 7 | exports['t01'] = function (test) { 8 | this.xw.startCData(); 9 | this.xw.text('fake'); 10 | this.xw.endCData(); 11 | test.equal(this.xw.toString(), ''); 12 | test.done(); 13 | }; 14 | exports['t02'] = function (test) { 15 | this.xw.startElement('tag'); 16 | this.xw.startCData(); 17 | this.xw.text('fake'); 18 | this.xw.endCData(); 19 | this.xw.text('value'); 20 | test.equal(this.xw.toString(), 'value'); 21 | test.done(); 22 | }; 23 | exports['t03'] = function (test) { 24 | this.xw.startElement('tag'); 25 | this.xw.startCData(); 26 | this.xw.startCData(); 27 | this.xw.text('fake'); 28 | this.xw.endCData(); 29 | this.xw.text('value'); 30 | this.xw.endCData(); 31 | this.xw.startCData(); 32 | this.xw.text('fake'); 33 | this.xw.endCData(); 34 | 35 | test.equal(this.xw.toString(), 'value'); 36 | test.done(); 37 | }; 38 | exports['t04'] = function (test) { 39 | this.xw.startElement('tag'); 40 | this.xw.startCData(); 41 | this.xw.startElement('tag'); 42 | this.xw.text('value'); 43 | this.xw.endElement(); 44 | this.xw.endCData(); 45 | this.xw.endElement(); 46 | test.equal(this.xw.toString(), 'value]]>'); 47 | 48 | test.done(); 49 | }; 50 | exports['t05'] = function (test) { 51 | test.done(); 52 | }; 53 | exports['t06'] = function (test) { 54 | this.xw.writeCData('value'); 55 | test.equal(this.xw.toString(), ''); 56 | test.done(); 57 | }; 58 | -------------------------------------------------------------------------------- /test/comments.js: -------------------------------------------------------------------------------- 1 | 2 | var XMLWriter = require('../'); 3 | exports['setUp'] = function (callback) { 4 | this.xw = new XMLWriter; 5 | callback(); 6 | }; 7 | exports['t01'] = function (test) { 8 | this.xw.startComment(); 9 | this.xw.text('fake'); 10 | this.xw.endComment(); 11 | test.equal(this.xw.toString(), ''); 12 | test.done(); 13 | }; 14 | exports['t02'] = function (test) { 15 | this.xw.startElement('tag'); 16 | this.xw.startComment(); 17 | this.xw.text('fake'); 18 | this.xw.endComment(); 19 | this.xw.text('value'); 20 | test.equal(this.xw.toString(), 'value'); 21 | test.done(); 22 | }; 23 | exports['t03'] = function (test) { 24 | this.xw.startElement('tag'); 25 | this.xw.startComment(); 26 | this.xw.startComment(); 27 | this.xw.text('fake'); 28 | this.xw.endComment(); 29 | this.xw.text('value'); 30 | this.xw.endComment(); 31 | this.xw.startComment(); 32 | this.xw.text('fake'); 33 | this.xw.endComment(); 34 | 35 | test.equal(this.xw.toString(), 'value'); 36 | test.done(); 37 | }; 38 | exports['t04'] = function (test) { 39 | this.xw.startElement('tag'); 40 | this.xw.startComment(); 41 | this.xw.startElement('tag'); 42 | this.xw.text('value'); 43 | this.xw.endElement(); 44 | this.xw.endComment(); 45 | this.xw.endElement(); 46 | test.equal(this.xw.toString(), ''); 47 | 48 | test.done(); 49 | }; 50 | exports['t05'] = function (test) { 51 | test.done(); 52 | }; 53 | exports['t06'] = function (test) { 54 | this.xw.writeComment('value'); 55 | test.equal(this.xw.toString(), ''); 56 | test.done(); 57 | }; 58 | exports['t06'] = function (test) { 59 | this.xw.writeComment(''); 60 | test.equal(this.xw.toString(), ''); 61 | test.done(); 62 | }; 63 | -------------------------------------------------------------------------------- /test/doctype.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter; 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.writeDocType('foo'); 8 | test.equal(this.xw.toString(), ''); 9 | test.done(); 10 | }; 11 | exports['t02'] = function (test) { 12 | this.xw.writeDocType('foo', null, 'http://localhost/foo'); 13 | test.equal(this.xw.toString(), ''); 14 | test.done(); 15 | }; 16 | exports['t03'] = function (test) { 17 | this.xw.writeDocType('foo', null, null, ''); 18 | test.equal(this.xw.toString(), ']>'); 19 | test.done(); 20 | }; 21 | exports['t04'] = function (test) { 22 | this.xw.writeDocType('html', "-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"); 23 | test.equal(this.xw.toString(), ''); 24 | test.done(); 25 | }; 26 | exports['t05'] = function (test) { 27 | test.throws(function(){ 28 | this.xw.writeDocType('foo', null, null, null); 29 | this.xw.startElement('bar'); 30 | }); 31 | test.done(); 32 | }; 33 | exports['t06'] = function (test) { 34 | this.xw.startElement('foo'); 35 | this.xw.writeDocType('foo', null, null, null); 36 | test.equal(this.xw.toString(), ''); 37 | test.done(); 38 | }; 39 | -------------------------------------------------------------------------------- /test/document.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter; 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.startDocument(); 8 | test.equal(this.xw.toString(), '\n'); 9 | test.done(); 10 | }; 11 | exports['t02'] = function (test) { 12 | this.xw.startDocument('1.0', 'utf-8'); 13 | test.equal(this.xw.toString(), '\n'); 14 | test.done(); 15 | }; 16 | exports['t03'] = function (test) { 17 | this.xw.startDocument('1.0', 'utf-8', true); 18 | test.equal(this.xw.toString(), '\n'); 19 | test.done(); 20 | }; 21 | exports['t04'] = function (test) { 22 | this.xw.startDocument(); 23 | this.xw.endDocument(); 24 | test.equal(this.xw.toString(), '\n'); 25 | test.done(); 26 | }; 27 | -------------------------------------------------------------------------------- /test/element.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter(); 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.startElement('foo'); 8 | test.equal(this.xw.toString(), ''); 9 | test.done(); 10 | }; 11 | exports['t02'] = function (test) { 12 | this.xw.startElement('foo'); 13 | this.xw.endElement(); 14 | test.equal(this.xw.toString(), ''); 15 | test.done(); 16 | }; 17 | exports['t03'] = function (test) { 18 | this.xw.startElement('foo'); 19 | this.xw.text('fake'); 20 | test.equal(this.xw.toString(), 'fake'); 21 | test.done(); 22 | }; 23 | exports['t04'] = function (test) { 24 | this.xw.startElement('foo'); 25 | this.xw.text('fake'); 26 | this.xw.endElement(); 27 | test.equal(this.xw.toString(), 'fake'); 28 | test.done(); 29 | }; 30 | exports['t05'] = function (test) { 31 | this.xw.writeElement('tag', 'value').endElement(); 32 | test.equal(this.xw.toString(), 'value'); 33 | test.done(); 34 | }; 35 | exports['t06'] = function (test) { 36 | this.xw.startElement('a'); 37 | this.xw.startElement('b'); 38 | this.xw.endElement(); 39 | this.xw.startElement('c'); 40 | this.xw.endElement(); 41 | this.xw.endElement(); 42 | test.equal(this.xw.toString(), ''); 43 | test.done(); 44 | }; 45 | -------------------------------------------------------------------------------- /test/misc.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter(); 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.startElement(function() {return 'toto'}).text(function() {return 'titi'}); 8 | test.equal(this.xw.toString(), 'titi'); 9 | test.done(); 10 | }; 11 | exports['t02'] = function (test) { 12 | test.throws(function(){this.xw.startElement('<>')}); 13 | test.done(); 14 | }; 15 | exports['t03'] = function (test) { 16 | this.xw.startElement('foo').text(''); 17 | test.equal(this.xw.toString(), '<toto>'); 18 | test.done(); 19 | }; 20 | exports['t03b'] = function (test) { 21 | this.xw.startElement('foo').text('un & deux & troie'); 22 | test.equal(this.xw.toString(), 'un & deux & troie'); 23 | test.done(); 24 | }; 25 | 26 | exports['t04'] = function (test) { 27 | this.xw.startElement('foo').writeAttribute('toto','"'); 28 | test.equal(this.xw.toString(), ''); 29 | test.done(); 30 | }; 31 | exports['t05'] = function (test) { 32 | this.xw.startElement('foo').writeAttribute('toto','&'); 33 | test.equal(this.xw.toString(), ''); 34 | test.done(); 35 | }; 36 | exports['t06'] = function (test) { 37 | this.xw.startElement('foo').writeAttribute('toto','&'); 38 | test.equal(this.xw.toString(), ''); 39 | test.done(); 40 | }; 41 | exports['t07'] = function (test) { 42 | this.xw.startElement('foo').writeAttribute('toto','"&'); 43 | test.equal(this.xw.toString(), ''); 44 | test.done(); 45 | }; 46 | exports['t08'] = function (test) { 47 | this.xw.startElement('foo').text(''); 48 | test.equal(this.xw.toString(), '<to&to>'); 49 | test.done(); 50 | }; 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /test/namespaces.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'); 2 | exports['setUp'] = function (callback) { 3 | this.xw = new XMLWriter(); 4 | callback(); 5 | }; 6 | exports['t01'] = function (test) { 7 | this.xw.startElement('t:foo'); 8 | test.equal(this.xw.toString(), ''); 9 | test.done(); 10 | }; 11 | exports['t03'] = function (test) { 12 | this.xw.startElement('foo:tag'); 13 | this.xw.text('fake'); 14 | test.equal(this.xw.toString(), 'fake'); 15 | test.done(); 16 | }; 17 | exports['t04'] = function (test) { 18 | this.xw.startElement('foo:tag'); 19 | this.xw.writeAttribute('foo:att', 'value'); 20 | this.xw.writeAttribute('att', 'value'); 21 | this.xw.text('fake'); 22 | this.xw.endElement(); 23 | test.equal(this.xw.toString(), 'fake'); 24 | test.done(); 25 | }; 26 | exports['t05'] = function (test) { 27 | this.xw.startDocument('1.0'); 28 | this.xw.startElement('rdf:RDF').writeAttribute('xmlns:rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#').writeAttribute('xmlns:cd', 'http://www.recshop.fake/cd#'); 29 | this.xw.startElement('rdf:Description').writeAttribute('rdf:about', 'http://www.recshop.fake/cd/Empire Burlesque'); 30 | this.xw.writeElement('cd:artist', 'Bob Dylan'); 31 | this.xw.writeElement('cd:country', 'USA'); 32 | this.xw.writeElement('cd:company', 'Columbia'); 33 | this.xw.writeElement('cd:price', '10.90'); 34 | this.xw.writeElement('cd:year', '1985'); 35 | this.xw.endElement(); 36 | this.xw.endElement(); 37 | this.xw.endDocument(); 38 | test.equal(this.xw.toString(), '\nBob DylanUSAColumbia10.901985'); 39 | test.done(); 40 | }; 41 | // With NS functions 42 | exports['t06'] = function (test) { 43 | this.xw.startElementNS('t','foo'); 44 | test.equal(this.xw.toString(), ''); 45 | test.done(); 46 | }; 47 | 48 | exports['t07'] = function (test) { 49 | this.xw.startElementNS('foo','tag'); 50 | this.xw.text('fake'); 51 | test.equal(this.xw.toString(), 'fake'); 52 | test.done(); 53 | }; 54 | exports['t08'] = function (test) { 55 | this.xw.startElementNS('foo','tag'); 56 | this.xw.writeAttributeNS('foo','att',null,'value'); 57 | this.xw.writeAttribute('att', 'value'); 58 | this.xw.text('fake'); 59 | this.xw.endElement(); 60 | test.equal(this.xw.toString(), 'fake'); 61 | test.done(); 62 | }; 63 | exports['t09'] = function (test) { 64 | this.xw.startDocument('1.0'); 65 | this.xw.startElementNS('rdf','RDF').writeAttributeNS('xmlns','rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#').writeAttributeNS('xmlns','cd', 'http://www.recshop.fake/cd#'); 66 | this.xw.startElementNS('rdf','Description').writeAttributeNS('rdf','about', 'http://www.recshop.fake/cd/Empire Burlesque'); 67 | this.xw.writeElementNS('cd','artist', null, 'Bob Dylan'); 68 | this.xw.writeElementNS('cd','country',null, 'USA'); 69 | this.xw.writeElementNS('cd','company', null, 'Columbia'); 70 | this.xw.writeElementNS('cd','price', null, '10.90'); 71 | this.xw.writeElementNS('cd','year', null,'1985'); 72 | this.xw.endElement(); 73 | this.xw.endElement(); 74 | this.xw.endDocument(); 75 | test.equal(this.xw.toString(), '\nBob DylanUSAColumbia10.901985'); 76 | test.done(); 77 | }; -------------------------------------------------------------------------------- /test/pi.js: -------------------------------------------------------------------------------- 1 | 2 | var XMLWriter = require('../'); 3 | exports['setUp'] = function (callback) { 4 | this.xw = new XMLWriter; 5 | callback(); 6 | }; 7 | exports['t01'] = function (test) { 8 | this.xw.startPI('php'); 9 | this.xw.endPI(); 10 | test.equal(this.xw.toString(), ''); 11 | test.done(); 12 | 13 | }; 14 | exports['t02'] = function (test) { 15 | this.xw.startPI('php'); 16 | this.xw.text(' echo'); 17 | this.xw.text(' __FILE__; '); 18 | this.xw.endPI(); 19 | test.equal(this.xw.toString(), ''); 20 | test.done(); 21 | }; 22 | exports['t03'] = function (test) { 23 | this.xw.startPI('xml-stylesheet'); 24 | this.xw.startAttribute('type'); 25 | this.xw.text('text/xml'); 26 | this.xw.endAttribute(); 27 | this.xw.startAttribute('href'); 28 | this.xw.text('style.xsl'); 29 | this.xw.endAttribute(); 30 | this.xw.endPI(); 31 | test.equal(this.xw.toString(), ''); 32 | test.done(); 33 | }; 34 | exports['t04'] = function (test) { 35 | test.done(); 36 | }; 37 | exports['t05'] = function (test) { 38 | this.xw.writePI('php', ' var_dump(__FILE__); '); 39 | test.equal(this.xw.toString(), ''); 40 | test.done(); 41 | }; 42 | -------------------------------------------------------------------------------- /test/raw.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'), 2 | fs = require('fs'); 3 | 4 | exports['t01'] = function (test) { 5 | this.xw = new XMLWriter( ); 6 | this.xw.startDocument('1.0', 'UTF-8'); 7 | this.xw.startElement('foo'); 8 | this.xw.writeRaw('1'); 9 | this.xw.startElement('two').text('2').endElement(); 10 | this.xw.endElement(); 11 | this.xw.endDocument(); 12 | 13 | test.equal(this.xw.toString(), '\n12'); 14 | test.done(); 15 | }; 16 | 17 | exports['t02'] = function (test) { 18 | var xw2 = new XMLWriter( ); 19 | xw2.startElement('one'); 20 | xw2.text('1'); 21 | xw2.endElement(); 22 | 23 | this.xw = new XMLWriter( ); 24 | this.xw.startDocument('1.0', 'UTF-8'); 25 | this.xw.startElement('foo'); 26 | this.xw.writeRaw(xw2); 27 | this.xw.startElement('two').text('2').endElement(); 28 | this.xw.endElement(); 29 | this.xw.endDocument(); 30 | 31 | test.equal(this.xw.toString(), '\n12'); 32 | test.done(); 33 | }; 34 | 35 | 36 | exports['t03'] = function (test) { 37 | function fragment() { 38 | var xw2 = new XMLWriter( ); 39 | xw2.startElement('one'); 40 | xw2.text('1'); 41 | xw2.endElement(); 42 | return xw2.toString(); 43 | } 44 | this.xw = new XMLWriter( ); 45 | this.xw.startDocument('1.0', 'UTF-8'); 46 | this.xw.startElement('foo'); 47 | this.xw.writeRaw(fragment()); 48 | this.xw.startElement('two').text('2').endElement(); 49 | this.xw.endElement(); 50 | this.xw.endDocument(); 51 | 52 | test.equal(this.xw.toString(), '\n12'); 53 | test.done(); 54 | }; 55 | -------------------------------------------------------------------------------- /test/writer.js: -------------------------------------------------------------------------------- 1 | var XMLWriter = require('../'), 2 | fs = require('fs'); 3 | 4 | exports['t01'] = function (test) { 5 | var filename = '/tmp/foo.xml'; 6 | var ws = fs.createWriteStream(filename); 7 | ws.on('close', function() { 8 | test.equal(fs.readFileSync(filename, 'UTF-8'), '\nà l\'école !'); 9 | test.done(); 10 | }); 11 | this.xw = new XMLWriter(false, function(s, e) { 12 | ws.write(s, e); 13 | }); 14 | this.xw.startDocument('1.0', 'UTF-8').startElement('foo').text('à l\'école !').endElement().endDocument(); 15 | ws.end(); 16 | }; 17 | --------------------------------------------------------------------------------