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 |
})();
|