Subversion Repositories munaweb

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/**
2
 * XMLWriter - XML generator for Javascript, based on .NET's XMLTextWriter.
3
 * Copyright (c) 2008-2014 Ariel Flesler - aflesler [a] gmail [d] com | http://flesler.blogspot.com
4
 * Licensed under BSD (https://raw2.github.com/flesler/XMLWriter/master/LICENSE)
5
 * @version 1.0.2
6
 * @author Ariel Flesler
7
 * http://flesler.blogspot.com/2008/03/xmlwriter-for-javascript.html
8
 */
9
 
10
function XMLWriter( encoding, version ){
11
	if( encoding )
12
		this.encoding = encoding;
13
	if( version )
14
		this.version = version;
15
};
16
(function(){
17
 
18
var proto = XMLWriter.prototype = {
19
	/* These are the defaults, you don't need to change them on the original code */
20
	encoding:'UTF-8',// what is the encoding
21
	version:'1.0', //what xml version to use
22
	formatting: 'indented', //how to format the output (indented/none)  ?
23
	indentChar:'\t', //char to use for indent
24
	indentation: 1, //how many indentChar to add per level
25
	newLine: '\n', //character to separate nodes when formatting
26
	/* */
27
	//start a new document, cleanup if we are reusing
28
	writeStartDocument:function( standalone ){
29
		this.close();//cleanup
30
		this.stack = [ ];
31
		this.standalone = standalone;
32
	},
33
	//get back to the root
34
	writeEndDocument:function(){
35
		this.active = this.root;
36
		this.stack = [ ];
37
	},
38
	//set the text of the doctype
39
	writeDocType:function( dt ){
40
		this.doctype = dt;
41
	},
42
	//start a new node with this name, and an optional namespace
43
	writeStartElement:function( name, ns ){
44
		if( ns )//namespace
45
			name = ns + ':' + name;
46
 
47
		var node = { n:name, a:{ }, c: [ ] };//(n)ame, (a)ttributes, (c)hildren
48
 
49
		if( this.active ){
50
			this.active.c.push(node);
51
			this.stack.push(this.active);
52
		}else
53
			this.root = node;
54
		this.active = node;
55
	},
56
	//go up one node, if we are in the root, ignore it
57
	writeEndElement:function(){
58
		this.active = this.stack.pop() || this.root;
59
	},
60
	//add an attribute to the active node
61
	writeAttributeString:function( name, value ){
62
		if( this.active )
63
			this.active.a[name] = value;
64
	},
65
	//add a text node to the active node
66
	writeString:function( text ){
67
		if( this.active )
68
			this.active.c.push(text);
69
	},
70
	//add plain xml content to the active node without any further checks and escaping
71
	writeXML:function( text ){
72
		if( this.active )
73
			this.active.c.push(text);
74
	},
75
	//shortcut, open an element, write the text and close
76
	writeElementString:function( name, text, ns ){
77
		this.writeStartElement( name, ns ) //take advantage of the chaining
78
			.writeString( text )
79
			.writeEndElement();
80
	},
81
	//add a text node wrapped with CDATA
82
	writeCDATA:function( text ){
83
		// keep nested CDATA
84
		text = text.replace(/>>]/g, "]]><![CDATA[>");
85
		this.writeString( '<![CDATA[' + text + ']]>' );
86
	},
87
	//add a text node wrapped in a comment
88
	writeComment:function( text ){
89
		this.writeString('<!-- ' + text + ' -->');
90
	},
91
	//generate the xml string, you can skip closing the last nodes
92
	flush:function(){
93
		this.writeEndDocument();//ensure it's closed
94
 
95
		var
96
			chr = '', num = this.indentation,
97
			formatting = this.formatting.toLowerCase() == 'indented',
98
			buffer = ['<?xml version="'+this.version+'" encoding="'+this.encoding+'"'];
99
 
100
		if( this.standalone !== undefined )
101
			buffer[0] += ' standalone="'+!!this.standalone+'"';
102
 
103
		buffer[0] += ' ?>';
104
 
105
		if( this.doctype && this.root )
106
			buffer.push('<!DOCTYPE '+ this.root.n + ' ' + this.doctype+'>');
107
 
108
		if( formatting ){
109
			while( num-- )
110
				chr += this.indentChar;
111
		}
112
 
113
		if( this.root )//skip if no element was added
114
			format( this.root, '', chr, buffer );
115
 
116
		return buffer.join( formatting ? this.newLine : '' );
117
	},
118
	//cleanup, don't use again without calling startDocument
119
	close:function(){
120
		if( this.root )
121
			clean( this.root );
122
		this.active = this.root = this.stack = null;
123
	},
124
	getDocument: window.ActiveXObject
125
		? function(){ //MSIE
126
			var doc = new ActiveXObject('Microsoft.XMLDOM');
127
			doc.async = false;
128
			doc.loadXML(this.flush());
129
			return doc;
130
		}
131
		: function(){//W3C
132
			return (new DOMParser()).parseFromString(this.flush(),'text/xml');
133
	}
134
};
135
 
136
//utility, you don't need it
137
function clean( node ){
138
	var l = node.c.length;
139
	while( l-- ){
140
		if( typeof node.c[l] == 'object' )
141
			clean( node.c[l] );
142
	}
143
	node.n = node.a = node.c = null;
144
};
145
 
146
//utility, you don't need it
147
function format( node, indent, chr, buffer ){
148
	var
149
		xml = indent + '<' + node.n,
150
		nc = node.c.length,
151
		attr, child, i = 0;
152
 
153
	for( attr in node.a )
154
		xml += ' ' + attr + '="' + node.a[attr] + '"';
155
 
156
	xml += nc ? '>' : ' />';
157
 
158
	buffer.push( xml );
159
 
160
	if( nc ){
161
		do{
162
			child = node.c[i++];
163
			if( typeof child == 'string' ){
164
				if( nc == 1 )//single text node
165
					return buffer.push( buffer.pop() + child + '</'+node.n+'>' );
166
				else //regular text node
167
					buffer.push( indent+chr+child );
168
			}else if( typeof child == 'object' ) //element node
169
				format(child, indent+chr, chr, buffer);
170
		}while( i < nc );
171
		buffer.push( indent + '</'+node.n+'>' );
172
	}
173
};
174
 
175
//add chaining! :)
176
for( var method in proto ){
177
	if( typeof proto[method] == 'function' && !/flush|getDocument/.test(method) ){
178
		var original = proto[method];
179
		proto[method] = function(){
180
			arguments.callee._o_.apply(this,arguments);
181
			return this;
182
		};
183
		proto[method]._o_ = original;
184
	}
185
}
186
 
187
})();