author | mullan |
Mon, 26 Sep 2011 17:20:45 -0700 | |
changeset 10694 | cf59e2badd14 |
parent 1337 | e8d6cef36199 |
child 18780 | f47b920867e7 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* reserved comment block |
|
3 |
* DO NOT REMOVE OR ALTER! |
|
4 |
*/ |
|
5 |
/* |
|
6 |
* Copyright 1999-2004 The Apache Software Foundation. |
|
7 |
* |
|
8 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
9 |
* you may not use this file except in compliance with the License. |
|
10 |
* You may obtain a copy of the License at |
|
11 |
* |
|
12 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
13 |
* |
|
14 |
* Unless required by applicable law or agreed to in writing, software |
|
15 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
16 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
17 |
* See the License for the specific language governing permissions and |
|
18 |
* limitations under the License. |
|
19 |
* |
|
20 |
*/ |
|
21 |
package com.sun.org.apache.xml.internal.security.signature; |
|
22 |
||
23 |
import java.io.IOException; |
|
24 |
import java.io.StringWriter; |
|
25 |
import java.io.Writer; |
|
26 |
import java.util.Arrays; |
|
27 |
import java.util.Set; |
|
28 |
||
29 |
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare; |
|
30 |
import com.sun.org.apache.xml.internal.security.utils.XMLUtils; |
|
31 |
import org.w3c.dom.Attr; |
|
32 |
import org.w3c.dom.Comment; |
|
33 |
import org.w3c.dom.Document; |
|
34 |
import org.w3c.dom.Element; |
|
35 |
import org.w3c.dom.NamedNodeMap; |
|
36 |
import org.w3c.dom.Node; |
|
37 |
import org.w3c.dom.ProcessingInstruction; |
|
38 |
||
39 |
/** |
|
40 |
* Class XMLSignatureInputDebugger |
|
41 |
* |
|
1337 | 42 |
* @author $Author: mullan $ |
43 |
* @version $Revision: 1.3 $ |
|
2 | 44 |
*/ |
45 |
public class XMLSignatureInputDebugger { |
|
46 |
||
47 |
||
48 |
||
49 |
/** Field _xmlSignatureInput */ |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
50 |
private Set<Node> _xpathNodeSet; |
2 | 51 |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
52 |
private Set<String> _inclusiveNamespaces; |
2 | 53 |
|
54 |
/** Field _doc */ |
|
55 |
private Document _doc = null; |
|
56 |
||
57 |
/** Field _writer */ |
|
58 |
private Writer _writer = null; |
|
59 |
||
60 |
// J- |
|
61 |
// public static final String HTMLPrefix = "<!DOCTYPE HTML PUBLIC |
|
62 |
// \"-//W3C//DTD HTML 4.01 Transitional//EN\"><html><head><style |
|
63 |
// type=\"text/css\"><!-- .INCLUDED { color: #000000; background-color: |
|
64 |
// #FFFFFF; font-weight: bold; } .EXCLUDED { color: #666666; |
|
65 |
// background-color: #999999; } .INCLUDEDINCLUSIVENAMESPACE { color: |
|
66 |
// #0000FF; background-color: #FFFFFF; font-weight: bold; font-style: |
|
67 |
// italic; } .EXCLUDEDINCLUSIVENAMESPACE { color: #0000FF; background-color: |
|
68 |
// #999999; font-style: italic; } --> </style> </head><body |
|
69 |
// bgcolor=\"#999999\"><pre>"; |
|
70 |
/** The HTML Prefix* */ |
|
71 |
static final String HTMLPrefix = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" |
|
72 |
+ "<html>\n" |
|
73 |
+ "<head>\n" |
|
74 |
+ "<title>Caninical XML node set</title>\n" |
|
75 |
+ "<style type=\"text/css\">\n" |
|
76 |
+ "<!-- \n" |
|
77 |
+ ".INCLUDED { \n" |
|
78 |
+ " color: #000000; \n" |
|
79 |
+ " background-color: \n" |
|
80 |
+ " #FFFFFF; \n" |
|
81 |
+ " font-weight: bold; } \n" |
|
82 |
+ ".EXCLUDED { \n" |
|
83 |
+ " color: #666666; \n" |
|
84 |
+ " background-color: \n" |
|
85 |
+ " #999999; } \n" |
|
86 |
+ ".INCLUDEDINCLUSIVENAMESPACE { \n" |
|
87 |
+ " color: #0000FF; \n" |
|
88 |
+ " background-color: #FFFFFF; \n" |
|
89 |
+ " font-weight: bold; \n" |
|
90 |
+ " font-style: italic; } \n" |
|
91 |
+ ".EXCLUDEDINCLUSIVENAMESPACE { \n" |
|
92 |
+ " color: #0000FF; \n" |
|
93 |
+ " background-color: #999999; \n" |
|
94 |
+ " font-style: italic; } \n" |
|
95 |
+ "--> \n" |
|
96 |
+ "</style> \n" |
|
97 |
+ "</head>\n" |
|
98 |
+ "<body bgcolor=\"#999999\">\n" |
|
99 |
+ "<h1>Explanation of the output</h1>\n" |
|
100 |
+ "<p>The following text contains the nodeset of the given Reference before it is canonicalized. There exist four different styles to indicate how a given node is treated.</p>\n" |
|
101 |
+ "<ul>\n" |
|
102 |
+ "<li class=\"INCLUDED\">A node which is in the node set is labeled using the INCLUDED style.</li>\n" |
|
103 |
+ "<li class=\"EXCLUDED\">A node which is <em>NOT</em> in the node set is labeled EXCLUDED style.</li>\n" |
|
104 |
+ "<li class=\"INCLUDEDINCLUSIVENAMESPACE\">A namespace which is in the node set AND in the InclusiveNamespaces PrefixList is labeled using the INCLUDEDINCLUSIVENAMESPACE style.</li>\n" |
|
105 |
+ "<li class=\"EXCLUDEDINCLUSIVENAMESPACE\">A namespace which is in NOT the node set AND in the InclusiveNamespaces PrefixList is labeled using the INCLUDEDINCLUSIVENAMESPACE style.</li>\n" |
|
106 |
+ "</ul>\n" + "<h1>Output</h1>\n" + "<pre>\n"; |
|
107 |
||
108 |
/** HTML Suffix * */ |
|
109 |
static final String HTMLSuffix = "</pre></body></html>"; |
|
110 |
||
111 |
static final String HTMLExcludePrefix = "<span class=\"EXCLUDED\">"; |
|
112 |
||
113 |
static final String HTMLExcludeSuffix = "</span>"; |
|
114 |
||
115 |
static final String HTMLIncludePrefix = "<span class=\"INCLUDED\">"; |
|
116 |
||
117 |
static final String HTMLIncludeSuffix = "</span>"; |
|
118 |
||
119 |
static final String HTMLIncludedInclusiveNamespacePrefix = "<span class=\"INCLUDEDINCLUSIVENAMESPACE\">"; |
|
120 |
||
121 |
static final String HTMLIncludedInclusiveNamespaceSuffix = "</span>"; |
|
122 |
||
123 |
static final String HTMLExcludedInclusiveNamespacePrefix = "<span class=\"EXCLUDEDINCLUSIVENAMESPACE\">"; |
|
124 |
||
125 |
static final String HTMLExcludedInclusiveNamespaceSuffix = "</span>"; |
|
126 |
||
127 |
private static final int NODE_BEFORE_DOCUMENT_ELEMENT = -1; |
|
128 |
||
129 |
private static final int NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT = 0; |
|
130 |
||
131 |
private static final int NODE_AFTER_DOCUMENT_ELEMENT = 1; |
|
132 |
||
133 |
static final AttrCompare ATTR_COMPARE = new AttrCompare(); |
|
134 |
||
135 |
// J+ |
|
136 |
private XMLSignatureInputDebugger() { |
|
137 |
// do nothing |
|
138 |
} |
|
139 |
||
140 |
/** |
|
141 |
* Constructor XMLSignatureInputDebugger |
|
142 |
* |
|
143 |
* @param xmlSignatureInput the signatur to pretty print |
|
144 |
*/ |
|
145 |
public XMLSignatureInputDebugger( |
|
146 |
XMLSignatureInput xmlSignatureInput) { |
|
147 |
||
148 |
if (!xmlSignatureInput.isNodeSet()) { |
|
149 |
this._xpathNodeSet = null; |
|
150 |
} else { |
|
151 |
this._xpathNodeSet = xmlSignatureInput._inputNodeSet; |
|
152 |
} |
|
153 |
} |
|
154 |
||
155 |
/** |
|
156 |
* Constructor XMLSignatureInputDebugger |
|
157 |
* |
|
158 |
* @param xmlSignatureInput the signatur to pretty print |
|
159 |
* @param inclusiveNamespace |
|
160 |
*/ |
|
161 |
public XMLSignatureInputDebugger( |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
162 |
XMLSignatureInput xmlSignatureInput, Set<String> inclusiveNamespace) { |
2 | 163 |
|
164 |
this(xmlSignatureInput); |
|
165 |
||
166 |
this._inclusiveNamespaces = inclusiveNamespace; |
|
167 |
} |
|
168 |
||
169 |
/** |
|
170 |
* Method getHTMLRepresentation |
|
171 |
* |
|
172 |
* @return The HTML Representation. |
|
173 |
* @throws XMLSignatureException |
|
174 |
*/ |
|
175 |
public String getHTMLRepresentation() throws XMLSignatureException { |
|
176 |
||
177 |
if ((this._xpathNodeSet == null) || (this._xpathNodeSet.size() == 0)) { |
|
178 |
return HTMLPrefix + "<blink>no node set, sorry</blink>" |
|
179 |
+ HTMLSuffix; |
|
180 |
} |
|
181 |
||
182 |
{ |
|
183 |
||
184 |
// get only a single node as anchor to fetch the owner document |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
185 |
Node n = this._xpathNodeSet.iterator().next(); |
2 | 186 |
|
187 |
this._doc = XMLUtils.getOwnerDocument(n); |
|
188 |
} |
|
189 |
||
190 |
try { |
|
191 |
this._writer = new StringWriter(); |
|
192 |
||
193 |
this.canonicalizeXPathNodeSet(this._doc); |
|
194 |
this._writer.close(); |
|
195 |
||
196 |
return this._writer.toString(); |
|
197 |
} catch (IOException ex) { |
|
198 |
throw new XMLSignatureException("empty", ex); |
|
199 |
} finally { |
|
200 |
this._xpathNodeSet = null; |
|
201 |
this._doc = null; |
|
202 |
this._writer = null; |
|
203 |
} |
|
204 |
} |
|
205 |
||
206 |
/** |
|
207 |
* Method canonicalizeXPathNodeSet |
|
208 |
* |
|
209 |
* @param currentNode |
|
210 |
* @throws XMLSignatureException |
|
211 |
* @throws IOException |
|
212 |
*/ |
|
213 |
private void canonicalizeXPathNodeSet(Node currentNode) |
|
214 |
throws XMLSignatureException, IOException { |
|
215 |
||
216 |
int currentNodeType = currentNode.getNodeType(); |
|
217 |
switch (currentNodeType) { |
|
218 |
||
219 |
case Node.DOCUMENT_TYPE_NODE: |
|
220 |
default: |
|
221 |
break; |
|
222 |
||
223 |
case Node.ENTITY_NODE: |
|
224 |
case Node.NOTATION_NODE: |
|
225 |
case Node.DOCUMENT_FRAGMENT_NODE: |
|
226 |
case Node.ATTRIBUTE_NODE: |
|
227 |
throw new XMLSignatureException("empty"); |
|
228 |
case Node.DOCUMENT_NODE: |
|
229 |
this._writer.write(HTMLPrefix); |
|
230 |
||
231 |
for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild |
|
232 |
.getNextSibling()) { |
|
233 |
this.canonicalizeXPathNodeSet(currentChild); |
|
234 |
} |
|
235 |
||
236 |
this._writer.write(HTMLSuffix); |
|
237 |
break; |
|
238 |
||
239 |
case Node.COMMENT_NODE: |
|
240 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
241 |
this._writer.write(HTMLIncludePrefix); |
|
242 |
} else { |
|
243 |
this._writer.write(HTMLExcludePrefix); |
|
244 |
} |
|
245 |
||
246 |
int position = getPositionRelativeToDocumentElement(currentNode); |
|
247 |
||
248 |
if (position == NODE_AFTER_DOCUMENT_ELEMENT) { |
|
249 |
this._writer.write("\n"); |
|
250 |
} |
|
251 |
||
252 |
this.outputCommentToWriter((Comment) currentNode); |
|
253 |
||
254 |
if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { |
|
255 |
this._writer.write("\n"); |
|
256 |
} |
|
257 |
||
258 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
259 |
this._writer.write(HTMLIncludeSuffix); |
|
260 |
} else { |
|
261 |
this._writer.write(HTMLExcludeSuffix); |
|
262 |
} |
|
263 |
break; |
|
264 |
||
265 |
case Node.PROCESSING_INSTRUCTION_NODE: |
|
266 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
267 |
this._writer.write(HTMLIncludePrefix); |
|
268 |
} else { |
|
269 |
this._writer.write(HTMLExcludePrefix); |
|
270 |
} |
|
271 |
||
272 |
position = getPositionRelativeToDocumentElement(currentNode); |
|
273 |
||
274 |
if (position == NODE_AFTER_DOCUMENT_ELEMENT) { |
|
275 |
this._writer.write("\n"); |
|
276 |
} |
|
277 |
||
278 |
this.outputPItoWriter((ProcessingInstruction) currentNode); |
|
279 |
||
280 |
if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { |
|
281 |
this._writer.write("\n"); |
|
282 |
} |
|
283 |
||
284 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
285 |
this._writer.write(HTMLIncludeSuffix); |
|
286 |
} else { |
|
287 |
this._writer.write(HTMLExcludeSuffix); |
|
288 |
} |
|
289 |
break; |
|
290 |
||
291 |
case Node.TEXT_NODE: |
|
292 |
case Node.CDATA_SECTION_NODE: |
|
293 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
294 |
this._writer.write(HTMLIncludePrefix); |
|
295 |
} else { |
|
296 |
this._writer.write(HTMLExcludePrefix); |
|
297 |
} |
|
298 |
||
299 |
outputTextToWriter(currentNode.getNodeValue()); |
|
300 |
||
301 |
for (Node nextSibling = currentNode.getNextSibling(); (nextSibling != null) |
|
302 |
&& ((nextSibling.getNodeType() == Node.TEXT_NODE) || (nextSibling |
|
303 |
.getNodeType() == Node.CDATA_SECTION_NODE)); nextSibling = nextSibling |
|
304 |
.getNextSibling()) { |
|
305 |
||
306 |
/* |
|
307 |
* The XPath data model allows to select only the first of a |
|
308 |
* sequence of mixed text and CDATA nodes. But we must output |
|
309 |
* them all, so we must search: |
|
310 |
* |
|
311 |
* @see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6329 |
|
312 |
*/ |
|
313 |
this.outputTextToWriter(nextSibling.getNodeValue()); |
|
314 |
} |
|
315 |
||
316 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
317 |
this._writer.write(HTMLIncludeSuffix); |
|
318 |
} else { |
|
319 |
this._writer.write(HTMLExcludeSuffix); |
|
320 |
} |
|
321 |
break; |
|
322 |
||
323 |
case Node.ELEMENT_NODE: |
|
324 |
Element currentElement = (Element) currentNode; |
|
325 |
||
326 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
327 |
this._writer.write(HTMLIncludePrefix); |
|
328 |
} else { |
|
329 |
this._writer.write(HTMLExcludePrefix); |
|
330 |
} |
|
331 |
||
332 |
this._writer.write("<"); |
|
333 |
this._writer.write(currentElement.getTagName()); |
|
334 |
||
335 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
336 |
this._writer.write(HTMLIncludeSuffix); |
|
337 |
} else { |
|
338 |
this._writer.write(HTMLExcludeSuffix); |
|
339 |
} |
|
340 |
||
341 |
// we output all Attrs which are available |
|
342 |
NamedNodeMap attrs = currentElement.getAttributes(); |
|
343 |
int attrsLength = attrs.getLength(); |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
344 |
Attr attrs2[] = new Attr[attrsLength]; |
2 | 345 |
|
346 |
for (int i = 0; i < attrsLength; i++) { |
|
10694
cf59e2badd14
7088502: Security libraries don't build with javac -Werror
mullan
parents:
1337
diff
changeset
|
347 |
attrs2[i] = (Attr)attrs.item(i); |
2 | 348 |
} |
349 |
||
350 |
Arrays.sort(attrs2, ATTR_COMPARE); |
|
351 |
Object attrs3[] = attrs2; |
|
352 |
||
353 |
for (int i = 0; i < attrsLength; i++) { |
|
354 |
Attr a = (Attr) attrs3[i]; |
|
355 |
boolean included = this._xpathNodeSet.contains(a); |
|
356 |
boolean inclusive = this._inclusiveNamespaces.contains(a |
|
357 |
.getName()); |
|
358 |
||
359 |
if (included) { |
|
360 |
if (inclusive) { |
|
361 |
||
362 |
// included and inclusive |
|
363 |
this._writer |
|
364 |
.write(HTMLIncludedInclusiveNamespacePrefix); |
|
365 |
} else { |
|
366 |
||
367 |
// included and not inclusive |
|
368 |
this._writer.write(HTMLIncludePrefix); |
|
369 |
} |
|
370 |
} else { |
|
371 |
if (inclusive) { |
|
372 |
||
373 |
// excluded and inclusive |
|
374 |
this._writer |
|
375 |
.write(HTMLExcludedInclusiveNamespacePrefix); |
|
376 |
} else { |
|
377 |
||
378 |
// excluded and not inclusive |
|
379 |
this._writer.write(HTMLExcludePrefix); |
|
380 |
} |
|
381 |
} |
|
382 |
||
383 |
this.outputAttrToWriter(a.getNodeName(), a.getNodeValue()); |
|
384 |
||
385 |
if (included) { |
|
386 |
if (inclusive) { |
|
387 |
||
388 |
// included and inclusive |
|
389 |
this._writer |
|
390 |
.write(HTMLIncludedInclusiveNamespaceSuffix); |
|
391 |
} else { |
|
392 |
||
393 |
// included and not inclusive |
|
394 |
this._writer.write(HTMLIncludeSuffix); |
|
395 |
} |
|
396 |
} else { |
|
397 |
if (inclusive) { |
|
398 |
||
399 |
// excluded and inclusive |
|
400 |
this._writer |
|
401 |
.write(HTMLExcludedInclusiveNamespaceSuffix); |
|
402 |
} else { |
|
403 |
||
404 |
// excluded and not inclusive |
|
405 |
this._writer.write(HTMLExcludeSuffix); |
|
406 |
} |
|
407 |
} |
|
408 |
} |
|
409 |
||
410 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
411 |
this._writer.write(HTMLIncludePrefix); |
|
412 |
} else { |
|
413 |
this._writer.write(HTMLExcludePrefix); |
|
414 |
} |
|
415 |
||
416 |
this._writer.write(">"); |
|
417 |
||
418 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
419 |
this._writer.write(HTMLIncludeSuffix); |
|
420 |
} else { |
|
421 |
this._writer.write(HTMLExcludeSuffix); |
|
422 |
} |
|
423 |
||
424 |
// traversal |
|
425 |
for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild |
|
426 |
.getNextSibling()) { |
|
427 |
this.canonicalizeXPathNodeSet(currentChild); |
|
428 |
} |
|
429 |
||
430 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
431 |
this._writer.write(HTMLIncludePrefix); |
|
432 |
} else { |
|
433 |
this._writer.write(HTMLExcludePrefix); |
|
434 |
} |
|
435 |
||
436 |
this._writer.write("</"); |
|
437 |
this._writer.write(currentElement.getTagName()); |
|
438 |
this._writer.write(">"); |
|
439 |
||
440 |
if (this._xpathNodeSet.contains(currentNode)) { |
|
441 |
this._writer.write(HTMLIncludeSuffix); |
|
442 |
} else { |
|
443 |
this._writer.write(HTMLExcludeSuffix); |
|
444 |
} |
|
445 |
break; |
|
446 |
} |
|
447 |
} |
|
448 |
||
449 |
/** |
|
450 |
* Checks whether a Comment or ProcessingInstruction is before or after the |
|
451 |
* document element. This is needed for prepending or appending "\n"s. |
|
452 |
* |
|
453 |
* @param currentNode |
|
454 |
* comment or pi to check |
|
455 |
* @return NODE_BEFORE_DOCUMENT_ELEMENT, |
|
456 |
* NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT or |
|
457 |
* NODE_AFTER_DOCUMENT_ELEMENT |
|
458 |
* @see #NODE_BEFORE_DOCUMENT_ELEMENT |
|
459 |
* @see #NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT |
|
460 |
* @see #NODE_AFTER_DOCUMENT_ELEMENT |
|
461 |
*/ |
|
462 |
private int getPositionRelativeToDocumentElement(Node currentNode) { |
|
463 |
||
464 |
if (currentNode == null) { |
|
465 |
return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; |
|
466 |
} |
|
467 |
||
468 |
Document doc = currentNode.getOwnerDocument(); |
|
469 |
||
470 |
if (currentNode.getParentNode() != doc) { |
|
471 |
return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; |
|
472 |
} |
|
473 |
||
474 |
Element documentElement = doc.getDocumentElement(); |
|
475 |
||
476 |
if (documentElement == null) { |
|
477 |
return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; |
|
478 |
} |
|
479 |
||
480 |
if (documentElement == currentNode) { |
|
481 |
return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; |
|
482 |
} |
|
483 |
||
484 |
for (Node x = currentNode; x != null; x = x.getNextSibling()) { |
|
485 |
if (x == documentElement) { |
|
486 |
return NODE_BEFORE_DOCUMENT_ELEMENT; |
|
487 |
} |
|
488 |
} |
|
489 |
||
490 |
return NODE_AFTER_DOCUMENT_ELEMENT; |
|
491 |
} |
|
492 |
||
493 |
/** |
|
494 |
* Normalizes an {@link Attr}ibute value |
|
495 |
* |
|
496 |
* The string value of the node is modified by replacing |
|
497 |
* <UL> |
|
498 |
* <LI>all ampersands (&) with <CODE>&amp;</CODE></LI> |
|
499 |
* <LI>all open angle brackets (<) with <CODE>&lt;</CODE></LI> |
|
500 |
* <LI>all quotation mark characters with <CODE>&quot;</CODE></LI> |
|
501 |
* <LI>and the whitespace characters <CODE>#x9</CODE>, #xA, and #xD, |
|
502 |
* with character references. The character references are written in |
|
503 |
* uppercase hexadecimal with no leading zeroes (for example, <CODE>#xD</CODE> |
|
504 |
* is represented by the character reference <CODE>&#xD;</CODE>)</LI> |
|
505 |
* </UL> |
|
506 |
* |
|
507 |
* @param name |
|
508 |
* @param value |
|
509 |
* @throws IOException |
|
510 |
*/ |
|
511 |
private void outputAttrToWriter(String name, String value) |
|
512 |
throws IOException { |
|
513 |
||
514 |
this._writer.write(" "); |
|
515 |
this._writer.write(name); |
|
516 |
this._writer.write("=\""); |
|
517 |
||
518 |
int length = value.length(); |
|
519 |
||
520 |
for (int i = 0; i < length; i++) { |
|
521 |
char c = value.charAt(i); |
|
522 |
||
523 |
switch (c) { |
|
524 |
||
525 |
case '&': |
|
526 |
this._writer.write("&amp;"); |
|
527 |
break; |
|
528 |
||
529 |
case '<': |
|
530 |
this._writer.write("&lt;"); |
|
531 |
break; |
|
532 |
||
533 |
case '"': |
|
534 |
this._writer.write("&quot;"); |
|
535 |
break; |
|
536 |
||
537 |
case 0x09: // '\t' |
|
538 |
this._writer.write("&#x9;"); |
|
539 |
break; |
|
540 |
||
541 |
case 0x0A: // '\n' |
|
542 |
this._writer.write("&#xA;"); |
|
543 |
break; |
|
544 |
||
545 |
case 0x0D: // '\r' |
|
546 |
this._writer.write("&#xD;"); |
|
547 |
break; |
|
548 |
||
549 |
default: |
|
550 |
this._writer.write(c); |
|
551 |
break; |
|
552 |
} |
|
553 |
} |
|
554 |
||
555 |
this._writer.write("\""); |
|
556 |
} |
|
557 |
||
558 |
/** |
|
559 |
* Normalizes a {@link org.w3c.dom.Comment} value |
|
560 |
* |
|
561 |
* @param currentPI |
|
562 |
* @throws IOException |
|
563 |
*/ |
|
564 |
private void outputPItoWriter(ProcessingInstruction currentPI) |
|
565 |
throws IOException { |
|
566 |
||
567 |
if (currentPI == null) { |
|
568 |
return; |
|
569 |
} |
|
570 |
||
571 |
this._writer.write("<?"); |
|
572 |
||
573 |
String target = currentPI.getTarget(); |
|
574 |
int length = target.length(); |
|
575 |
||
576 |
for (int i = 0; i < length; i++) { |
|
577 |
char c = target.charAt(i); |
|
578 |
||
579 |
switch (c) { |
|
580 |
||
581 |
case 0x0D: |
|
582 |
this._writer.write("&#xD;"); |
|
583 |
break; |
|
584 |
||
585 |
case ' ': |
|
586 |
this._writer.write("·"); |
|
587 |
break; |
|
588 |
||
589 |
case '\n': |
|
590 |
this._writer.write("¶\n"); |
|
591 |
break; |
|
592 |
||
593 |
default: |
|
594 |
this._writer.write(c); |
|
595 |
break; |
|
596 |
} |
|
597 |
} |
|
598 |
||
599 |
String data = currentPI.getData(); |
|
600 |
||
601 |
length = data.length(); |
|
602 |
||
1337 | 603 |
if (length > 0) { |
604 |
this._writer.write(" "); |
|
2 | 605 |
|
1337 | 606 |
for (int i = 0; i < length; i++) { |
607 |
char c = data.charAt(i); |
|
2 | 608 |
|
1337 | 609 |
switch (c) { |
2 | 610 |
|
1337 | 611 |
case 0x0D: |
612 |
this._writer.write("&#xD;"); |
|
613 |
break; |
|
2 | 614 |
|
1337 | 615 |
default: |
616 |
this._writer.write(c); |
|
617 |
break; |
|
2 | 618 |
} |
1337 | 619 |
} |
2 | 620 |
} |
621 |
||
622 |
this._writer.write("?>"); |
|
623 |
} |
|
624 |
||
625 |
/** |
|
626 |
* Method outputCommentToWriter |
|
627 |
* |
|
628 |
* @param currentComment |
|
629 |
* @throws IOException |
|
630 |
*/ |
|
631 |
private void outputCommentToWriter(Comment currentComment) |
|
632 |
throws IOException { |
|
633 |
||
634 |
if (currentComment == null) { |
|
635 |
return; |
|
636 |
} |
|
637 |
||
638 |
this._writer.write("<!--"); |
|
639 |
||
640 |
String data = currentComment.getData(); |
|
641 |
int length = data.length(); |
|
642 |
||
643 |
for (int i = 0; i < length; i++) { |
|
644 |
char c = data.charAt(i); |
|
645 |
||
646 |
switch (c) { |
|
647 |
||
648 |
case 0x0D: |
|
649 |
this._writer.write("&#xD;"); |
|
650 |
break; |
|
651 |
||
652 |
case ' ': |
|
653 |
this._writer.write("·"); |
|
654 |
break; |
|
655 |
||
656 |
case '\n': |
|
657 |
this._writer.write("¶\n"); |
|
658 |
break; |
|
659 |
||
660 |
default: |
|
661 |
this._writer.write(c); |
|
662 |
break; |
|
663 |
} |
|
664 |
} |
|
665 |
||
666 |
this._writer.write("-->"); |
|
667 |
} |
|
668 |
||
669 |
/** |
|
670 |
* Method outputTextToWriter |
|
671 |
* |
|
672 |
* @param text |
|
673 |
* @throws IOException |
|
674 |
*/ |
|
675 |
private void outputTextToWriter(String text) throws IOException { |
|
676 |
||
677 |
if (text == null) { |
|
678 |
return; |
|
679 |
} |
|
680 |
||
681 |
int length = text.length(); |
|
682 |
||
683 |
for (int i = 0; i < length; i++) { |
|
684 |
char c = text.charAt(i); |
|
685 |
||
686 |
switch (c) { |
|
687 |
||
688 |
case '&': |
|
689 |
this._writer.write("&amp;"); |
|
690 |
break; |
|
691 |
||
692 |
case '<': |
|
693 |
this._writer.write("&lt;"); |
|
694 |
break; |
|
695 |
||
696 |
case '>': |
|
697 |
this._writer.write("&gt;"); |
|
698 |
break; |
|
699 |
||
700 |
case 0xD: |
|
701 |
this._writer.write("&#xD;"); |
|
702 |
break; |
|
703 |
||
704 |
case ' ': |
|
705 |
this._writer.write("·"); |
|
706 |
break; |
|
707 |
||
708 |
case '\n': |
|
709 |
this._writer.write("¶\n"); |
|
710 |
break; |
|
711 |
||
712 |
default: |
|
713 |
this._writer.write(c); |
|
714 |
break; |
|
715 |
} |
|
716 |
} |
|
717 |
} |
|
718 |
} |