123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- var toXML = function(obj, config){
- // include XML header
- config = config || {};
- var out = '';
- if(config.header) {
- if(typeof config.header == 'string') {
- out = config.header;
- } else {
- out = '<?xml version="1.0" encoding="UTF-8"?>\n';
- }
- }
-
- var origIndent = config.indent || '';
- var indent = '';
- var filter = function customFilter(txt) {
- if(!config.filter) return txt;
- var mappings = config.filter;
- var replacements = [];
- for(var map in mappings) {
- if(!mappings.hasOwnProperty(map)) continue;
- replacements.push(map);
- }
- return String(txt).replace(new RegExp('(' + replacements.join('|') + ')', 'g'), function(str, entity) {
- return mappings[entity] || '';
- });
- };
-
- // helper function to push a new line to the output
- var push = function(string){
- out += string + (origIndent ? '\n' : '');
- };
-
- /* create a tag and add it to the output
- Example:
- outputTag({
- name: 'myTag', // creates a tag <myTag>
- indent: ' ', // indent string to prepend
- closeTag: true, // starts and closes a tag on the same line
- selfCloseTag: true,
- attrs: { // attributes
- foo: 'bar', // results in <myTag foo="bar">
- foo2: 'bar2'
- }
- });
- */
- var outputTag = function(tag){
- var attrsString = '';
- var outputString = '';
- var attrs = tag.attrs || '';
-
- // turn the attributes object into a string with key="value" pairs
- for(var attr in attrs){
- if(attrs.hasOwnProperty(attr)) {
- attrsString += ' ' + attr + '="' + attrs[attr] + '"';
- }
- }
- // assemble the tag
- outputString += (tag.indent || '') + '<' + (tag.closeTag ? '/' : '') + tag.name + (!tag.closeTag ? attrsString : '') + (tag.selfCloseTag ? '/' : '') + '>';
-
- // if the tag only contains a text string, output it and close the tag
- if(tag.text || tag.text === ''){
- outputString += filter(tag.text) + '</' + tag.name + '>';
- }
-
- push(outputString);
- };
-
- // custom-tailored iterator for input arrays/objects (NOT a general purpose iterator)
- var every = function(obj, fn, indent){
- // array
- if(Array.isArray(obj)){
- obj.every(function(elt){ // for each element in the array
- fn(elt, indent);
- return true; // continue to iterate
- });
-
- return;
- }
-
- // object with tag name
- if(obj._name){
- fn(obj, indent);
- return;
- }
-
- // iterable object
- for(var key in obj){
- var type = typeof obj[key];
- if(obj.hasOwnProperty(key) && (obj[key] || type === 'boolean' || type === 'number')){
- fn({_name: key, _content: obj[key]}, indent);
- //} else if(!obj[key]) { // null value (foo:'')
- } else if(obj.hasOwnProperty(key) && obj[key] === null) { // null value (foo:null)
- fn(key, indent); // output the keyname as a string ('foo')
- } else if(obj.hasOwnProperty(key) && obj[key] === '') {
- // blank string
- outputTag({
- name: key,
- text: ''
- });
- }
- }
- };
-
- var convert = function convert(input, indent){
- var type = typeof input;
-
- if(!indent) indent = '';
-
- if(Array.isArray(input)) type = 'array';
-
- var path = {
- 'string': function(){
- push(indent + filter(input));
- },
- 'boolean': function(){
- push(indent + (input ? 'true' : 'false'));
- },
-
- 'number': function(){
- push(indent + input);
- },
-
- 'array': function(){
- every(input, convert, indent);
- },
-
- 'function': function(){
- push(indent + input());
- },
-
- 'object': function(){
- if(!input._name){
- every(input, convert, indent);
- return;
- }
-
- var outputTagObj = {
- name: input._name,
- indent: indent,
- attrs: input._attrs
- };
-
- var type = typeof input._content;
- if(type === 'undefined' || input._content._selfCloseTag === true){
- if (input._content && input._content._attrs) {
- outputTagObj.attrs = input._content._attrs;
- }
- outputTagObj.selfCloseTag = true;
- outputTag(outputTagObj);
- return;
- }
-
- var objContents = {
- 'string': function(){
- outputTagObj.text = input._content;
- outputTag(outputTagObj);
- },
- 'boolean': function(){
- outputTagObj.text = (input._content ? 'true' : 'false');
- outputTag(outputTagObj);
- },
-
- 'number': function(){
- outputTagObj.text = input._content.toString();
- outputTag(outputTagObj);
- },
-
- 'object': function(){ // or Array
- outputTag(outputTagObj);
-
- every(input._content, convert, indent + origIndent);
-
- outputTagObj.closeTag = true;
- outputTag(outputTagObj);
- },
-
- 'function': function(){
- outputTagObj.text = input._content(); // () to execute the fn
- outputTag(outputTagObj);
- }
- };
-
- if(objContents[type]) objContents[type]();
- }
-
- };
-
- if(path[type]) path[type]();
- };
-
- convert(obj, indent);
-
- return out;
- };
- exports.toXML = toXML;
|