Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: Source/core/xml/XMLSerializer.js

Issue 534583002: Implemented XMLSerializer in PrivateScript. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/xml/XMLSerializer.idl ('k') | public/blink_resources.grd » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 installClass('XMLSerializer', function(XMLSerializerPrototype) {
8
9 var EMPTY = '';
10
11 var XML_NAMESPACE_URI = 'http://www.w3.org/XML/1998/namespace';
12 var XLINK_NAMESPACE_URI = 'http://www.w3.org/1999/xlink';
13 var XMLNS_NAMESPACE_URI = 'http://www.w3.org/2000/xmlns';
14 var HTML_NAMESPACE_URI = 'http://www.w3.org/1999/xhtml';
15
16 var SERIALIZATION_TYPE_AS_OWNER_DOCUMENT = 0;
17 var SERIALIZATION_TYPE_FORCED_XML = 1;
18
19 function escapePCDATA(text) {
20 return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, ' &gt;');
21 }
22
23 function escapeHTMLPCDATA(text) {
24 return escapePCDATA(text).replace(/\u00A0/g, '&nbsp;');
25 }
26
27 function escapeAttributeValue(text) {
28 return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
29 }
30
31 function escapeHTMLAttributeValue(text) {
32 text.replace(/&|"|\u00A0/g, function(c) {
33 switch (c) {
34 case '&': return '&amp;';
35 case '"': return '&quot;';
36 case '\u00A0': return '&nbsp;';
37 }
38 });
39 }
40
41 function validateURI(uri) {
42 return uri ? uri.replace(/\/$/g, '') : '';
43 }
44
45 function cloneNamespace(obj) {
46 var clone = Object.create(null);
47 for (var i in obj)
48 clone[i] = obj[i];
49 return clone;
50 }
51
52 function isTemplateElement(node) {
53 return isHTMLElement(node) && node.localName == 'template';
54 }
55
56 function generatePrefix(namespaces) {
57 var nsRegex = /^ns([0-9]+)$/g;
58 var maxValue = 0;
59 for (var key in namespaces) {
60 var match = nsRegex.exec(key);
61 if (match) {
62 var value = parseInt(match[1], 10);
63 if (maxValue < value)
64 maxValue = value;
65 }
66 }
67 return 'ns' + (maxValue + 1);
68 }
69
70 function qualifiedTagName(node) {
71 return isHTMLElement(node) ? node.localName : node.tagName;
72 }
73
74 var SERIALIZED_NAMESPACES = {
75 XML_NAMESPACE_URI: true,
76 XLINK_NAMESPACE_URI: true,
77 XMLNS_NAMESPACE_URI: true
78 };
79
80 function attributeIsInSerializedNamespace(attr) {
81 return SERIALIZED_NAMESPACES[validateURI(attr.namespaceURI)];
82 }
83
84 function appendNamespace(prefix, namespaceURI, namespaces) {
85 if (!namespaceURI)
86 return '';
87
88 var result = '';
89 var lookupKey = EMPTY;
90 if (prefix)
91 lookupKey = prefix;
92 if (namespaces[lookupKey] != namespaceURI) {
93 namespaces[lookupKey] = namespaceURI;
94 result += ' xmlns';
95 if (prefix)
96 result += ':' + prefix;
97 result += '="' + namespaceURI + '"';
98 }
99 return result;
100 }
101
102 function shouldAddNamespaceAttribute(attr, node) {
103 if (!attr.namespaceURI)
104 return false;
105 if (!attr.prefix)
106 return true;
107 if (!node.hasAttribute('xmlns:' + attr.prefix))
108 return true;
109 return false;
110 }
111
112 function shouldAddNamespaceElement(node, namespaces) {
113 var prefix = node.prefix;
114 if (!node.prefix) {
115 if (node.hasAttribute('xmlns')) {
116 namespaces[EMPTY] = node.namespaceURI;
117 return false;
118 }
119 return true;
120 }
121 if (!node.hasAttribute('xmlns:' + node.prefix))
122 return true;
123 return false;
124 }
125
126 function isHTMLElement(node) {
127 if (node.nodeType != Node.ELEMENT_NODE)
128 return false;
129
130 for (var runner = node; runner; runner = runner.parentNode) {
131 if (runner.nodeType == Node.ELEMENT_NODE && runner.namespaceURI != n ull)
132 return validateURI(runner.namespaceURI) == HTML_NAMESPACE_URI;
133 }
134 return false;
135 }
136
137 // This tables comes from HTMLElement::ieForbidsInsertHTML().
138 var END_TAG_OMISSIBLE_TAGS = {
139 'area': true, 'base': true, 'basefont': true, 'br': true,
140 'col': true, 'embed': true, 'frame': true, 'hr': true,
141 'image': true, 'img': true, 'input': true, 'link': true,
142 'meta': true, 'param': true, 'source': true, 'wbr': true
143 };
144
145 function isEndTagOmissible(node) {
146 if (node.nodeType != Node.ELEMENT_NODE)
147 return false;
148 return END_TAG_OMISSIBLE_TAGS[node.localName];
149 }
150
151 XMLSerializerPrototype.serializeAsHTMLDocument_ = function(node) {
152 if (this.serializationType_ == SERIALIZATION_TYPE_FORCED_XML)
153 return false;
154 return node.ownerDocument && (node.ownerDocument instanceof HTMLDocument );
155 };
156
157 XMLSerializerPrototype.serializeAttribute_ = function(node, attr, namespaces ) {
158 var documentIsHTML = this.serializeAsHTMLDocument_(node);
159 var result = '';
160
161 var attrPrefix = attr.prefix;
162 var attrName = attr.localName;
163 if (documentIsHTML && !attributeIsInSerializedNamespace(attr)) {
164 result += ' ' + attr.localName;
165 } else {
166 var namespaceURI = validateURI(attr.namespaceURI);
167 if (namespaceURI == XMLNS_NAMESPACE_URI) {
168 if (!attr.prefix && attr.localName != 'xmlns')
169 attrPrefix = 'xmlns';
170 if (namespaces) {
171 var lookupKey = EMPTY;
172 if (attr.prefix)
173 lookupKey = attr.localName;
174 namespaces[lookupKey] = attr.value;
175 }
176 } else if (namespaceURI == XML_NAMESPACE_URI) {
177 if (!attr.prefix)
178 attrPrefix = 'xml';
179 } else {
180 if (namespaceURI == XLINK_NAMESPACE_URI) {
181 if (!attr.prefix)
182 attrPrefix = 'xlink';
183 }
184 if (namespaces && shouldAddNamespaceAttribute(attr, node)) {
185 if (!attrPrefix) {
186 for (var i in namespaces) {
187 if (namespaces[i] == namespaceURI && i) {
188 attrPrefix = i;
189 break;
190 }
191 }
192 if (!attrPrefix)
193 attrPrefix = generatePrefix(namespaces);
194 }
195 result += appendNamespace(attrPrefix, namespaceURI, namespac es);
196 }
197 }
198 if (attrPrefix) {
199 result += ' ' + attrPrefix + ':' + attrName;
200 } else {
201 result += ' ' + attrName;
202 }
203 }
204 if (attr.value) {
205 var attrValue;
206 if (documentIsHTML) {
207 attrValue = escapeHTMLAttributeValue(String(attr.value));
208 } else {
209 attrValue = escapeAttributeValue(String(attr.value));
210 }
211 result += '="' + attrValue + '"';
212 }
213 return result;
214 };
215
216 XMLSerializerPrototype.serializeAttributes_ = function(node, namespaces) {
217 if (!node.attributes)
218 return '';
219
220 var sink = '';
221 for (var i = 0; i < node.attributes.length; ++i)
222 sink += this.serializeAttribute_(node, node.attributes[i], namespace s);
223 return sink;
224 };
225
226 XMLSerializerPrototype.serializeOpenTag_ = function(node, namespaces) {
227 var sink = '<' + qualifiedTagName(node);
228 if (!this.serializeAsHTMLDocument_(node) && namespaces && shouldAddNames paceElement(node, namespaces))
229 sink += appendNamespace(node.prefix, node.namespaceURI, namespaces);
230 return sink;
231 };
232
233 XMLSerializerPrototype.serializeCloseTag_ = function(node, namespaces) {
234 var sink = '';
235 if (this.shouldSelfClose_(node)) {
236 if (isHTMLElement(node))
237 sink += ' ';
238 sink += '/';
239 }
240 sink += '>';
241 return sink;
242 };
243
244 XMLSerializerPrototype.serializeElement_ = function(node, namespaces) {
245 return this.serializeOpenTag_(node, namespaces) +
246 this.serializeAttributes_(node, namespaces) +
247 this.serializeCloseTag_(node, namespaces);
248 };
249
250 XMLSerializerPrototype.serializeText_ = function(node) {
251 if (!node.nodeValue)
252 return '';
253
254 if (this.serializeAsHTMLDocument_(node)) {
255 if (node.parentNode && isHTMLElement(node.parentNode)) {
256 var tagName = node.parentNode.localName;
257 if (tagName == 'script' || tagName == 'style' || tagName == 'xmp ')
258 return node.nodeValue;
259 }
260 return escapeHTMLPCDATA(node.nodeValue);
261 }
262 return escapePCDATA(node.nodeValue);
263 };
264
265 XMLSerializerPrototype.serializeComment_ = function(node) {
266 return '<!--' + node.nodeValue + '-->';
267 };
268
269 XMLSerializerPrototype.serializeDocument_ = function(node) {
270 return this.documentXMLDeclaration_;
271 };
272
273 XMLSerializerPrototype.serializeDocumentType_ = function(node) {
274 var s = '<!DOCTYPE ' + node.name;
275 if (node.publicId) {
276 s += ' PUBLIC "' + node.publicId + '"';
277 if (node.systemId)
278 s += ' "' + node.systemId + '"';
279 } else if (node.systemId) {
280 s += ' SYSTEM "' + node.systemId + '"';
281 }
282 s += '>';
283 return s;
284 };
285
286 XMLSerializerPrototype.serializeProcessingInstruction_ = function(node) {
287 var s = '<?' + node.target;
288 if (node.nodeValue)
289 s += ' ' + node.nodeValue;
290 s += '?>';
291 return s;
292 };
293
294 XMLSerializerPrototype.serializeCDataSection_ = function(node) {
295 return '<![CDATA[' + node.nodeValue + ']]>';
296 };
297
298 XMLSerializerPrototype.serializeStartTag = function(node, namespaces) {
299 switch (node.nodeType) {
300 case Node.TEXT_NODE:
301 return this.serializeText_(node);
302 case Node.COMMENT_NODE:
303 return this.serializeComment_(node);
304 case Node.DOCUMENT_NODE:
305 return this.serializeDocument_(node);
306 case Node.DOCUMENT_TYPE_NODE:
307 return this.serializeDocumentType_(node);
308 case Node.PROCESSING_INSTRUCTION_NODE:
309 return this.serializeProcessingInstruction_(node);
310 case Node.ELEMENT_NODE:
311 return this.serializeElement_(node, namespaces);
312 case Node.CDATA_SECTION_NODE:
313 return this.serializeCDataSection_(node);
314 case Node.DOCUMENT_FRAGMENT_NODE:
315 default:
316 return '';
317 }
318 };
319
320 XMLSerializerPrototype.shouldSelfClose_ = function(node) {
321 if (this.serializeAsHTMLDocument_(node))
322 return false;
323 if (node.hasChildNodes())
324 return false;
325 if (isTemplateElement(node) && node.content && node.content.hasChildNode s())
326 return false;
327 if (isHTMLElement(node) && !isEndTagOmissible(node))
328 return false;
329 return true;
330 };
331
332 XMLSerializerPrototype.serializeEndTag_ = function(node) {
333 if (this.shouldSelfClose_(node) || (!node.hasChildNodes() && isEndTagOmi ssible(node)))
334 return '';
335 return '</' + qualifiedTagName(node) + '>';
336 };
337
338 XMLSerializerPrototype.serializeNodesWithNamespaces_ = function(node, namesp aces) {
339 var sink = '';
340 var localNamespaces = cloneNamespace(namespaces);
341 sink += this.serializeStartTag(node, localNamespaces);
342
343 if (!(this.serializeAsHTMLDocument_(node) && isEndTagOmissible(node))) {
344 var current = node;
345 if (isTemplateElement(node))
346 current = node.content;
347 current = current.firstChild;
348 while (current) {
349 sink += this.serializeNodesWithNamespaces_(current, localNamespa ces);
350 current = current.nextSibling;
351 }
352 }
353 if (node.nodeType == Node.ELEMENT_NODE)
354 sink += this.serializeEndTag_(node);
355 return sink;
356 };
357
358 XMLSerializerPrototype.serializeNodes_ = function(node) {
359 var namespaces = Object.create(null);
360 if (!this.serializeAsHTMLDocument_(node)) {
361 namespaces['xml'] = XML_NAMESPACE_URI;
362 namespaces['xmlns'] = XMLNS_NAMESPACE_URI;
363 }
364
365 return this.serializeNodesWithNamespaces_(node, namespaces);
366 };
367
368 XMLSerializerPrototype.serializeToStringForPrivateScript = function(root, xm lDeclaration) {
tasak 2014/10/08 12:04:26 Done.
369 this.serializationType_ = SERIALIZATION_TYPE_FORCED_XML;
370 this.documentXMLDeclaration_ = xmlDeclaration;
371 return this.serializeNodes_(root);
372 };
373 });
OLDNEW
« no previous file with comments | « Source/core/xml/XMLSerializer.idl ('k') | public/blink_resources.grd » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698