1 /*
2 * The Apache Software License, Version 1.1
3 *
4 *
5 * Copyright (c) 1999 The Apache Software Foundation. All rights
6 * reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Apache Software Foundation (http://www.apache.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Xerces" and "Apache Software Foundation" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact apache@apache.org.
31 *
32 * 5. Products derived from this software may not be called "Apache",
33 * nor may "Apache" appear in their name, without prior written
34 * permission of the Apache Software Foundation.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the Apache Software Foundation and was
52 * originally based on software copyright (c) 1999, International
53 * Business Machines, Inc., http://www.apache.org. For more
54 * information on the Apache Software Foundation, please see
55 * <http://www.apache.org/>.
56 */
57 package dom.range;
58 import org.apache.xerces.parsers;
59 import org.apache.xerces.dom;
60 import org.apache.xerces.dom.DocumentImpl;
61
62 import org.w3c.dom;
63 import org.w3c.dom.Element;
64 import org.w3c.dom.range;
65 import org.w3c.dom.range.RangeException;
66
67 import java.io;
68 import dom.DOMWriter;
69 import org.xml.sax.InputSource;
70
71 /** This RangeTest tests all of the cases delineated as examples
72 * in the DOM Level 2 Range specification, and a few others.
73 * <p>These do not by any means completely test the API and
74 * corner cases.
75 */
76 public class Test {
77
78 static final boolean DEBUG = false;
79
80 static final String [] tests = {
81 "<FOO>AB<MOO>CD</MOO>CD</FOO>",
82 "<FOO>A<MOO>BC</MOO>DE</FOO>",
83 "<FOO>XY<BAR>ZW</BAR>Q</FOO>",
84 "<FOO><BAR1>AB</BAR1><BAR2/><BAR3>CD</BAR3></FOO>",
85 "<A><B><M/><C><D/><E/><F/><HELLO/></C><N/><O/></B>"+
86 "<Z><X/><Y/></Z>"+
87 "<G/><Q><V/><W/></Q></A>"
88 };
89 static final String [] deleteResult = {
90 "<FOO>ACD</FOO>",
91 "<FOO>A<MOO>B</MOO>E</FOO>",
92 "<FOO>X<BAR>W</BAR>Q</FOO>",
93 "<FOO><BAR1>A</BAR1><BAR3>D</BAR3></FOO>",
94 "<A><B><M></M><C><D></D></C></B><Q><W></W></Q></A>"
95 };
96 static final String [] extractResult = {
97 "B<MOO>CD</MOO>",
98 "<MOO>C</MOO>D",
99 "Y<BAR>Z</BAR>",
100 "<BAR1>B</BAR1><BAR2></BAR2><BAR3>C</BAR3>",
101 "<B><C><E></E><F></F><HELLO></HELLO></C>"+
102 "<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V></Q>"
103 };
104
105 static final String INSERT="***";
106 static final String [] insertResult = {
107 "<FOO>A"+INSERT+"B<MOO>CD</MOO>CD</FOO>",
108 "<FOO>A<MOO>B"+INSERT+"C</MOO>DE</FOO>",
109 "<FOO>X"+INSERT+"Y<BAR>ZW</BAR>Q</FOO>",
110 "<FOO><BAR1>A"+INSERT+"B</BAR1><BAR2></BAR2><BAR3>CD</BAR3></FOO>",
111 "<A><B><M></M><C><D></D>"+INSERT+"<E></E><F></F><HELLO></HELLO></C>"+
112 "<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V><W></W></Q></A>"
113 };
114
115
116 static final String SURROUND="SURROUND";
117
118 static final String [] surroundResult = {
119 "<FOO>A<"+SURROUND+">B<MOO>CD</MOO>C</"+SURROUND+">D</FOO>",
120 "<FOO>A<MOO>B<"+SURROUND+">C</"+SURROUND+"></MOO>DE</FOO>",
121 "<FOO>X<"+SURROUND+">Y<BAR>ZW</BAR></"+SURROUND+">Q</FOO>",
122 "<FOO><BAR1>AB</BAR1><"+SURROUND+"><BAR2></BAR2></"+SURROUND+"><BAR3>CD</BAR3></FOO>",
123 "<A><B><M></M><C><D></D><E></E><F></F><HELLO></HELLO></C>"+
124 "<N></N><O></O></B><Z><"+SURROUND+"><X></X><Y></Y></"+SURROUND+"></Z>"+
125 "<G></G><Q><V></V><W></W></Q></A>"
126 };
127
128 static final String [] rangeDelete = {
129 "<P>Abcd efgh The Range ijkl</P>",
130 "<p>Abcd efgh The Range ijkl</p>",
131 "<P>ABCD efgh The <EM>Range</EM> ijkl</P>",
132 "<P>Abcd efgh The Range ijkl</P>",
133 "<P>Abcd <EM>efgh The Range ij</EM>kl</P>"
134 };
135 //
136 static final String [] rangeDeleteResult = {
137 "<P>Abcd ^Range ijkl</P>",
138 "<p>Abcd ^kl</p>",
139 "<P>ABCD ^<EM>ange</EM> ijkl</P>",
140 "<P>Abcd ^he Range ijkl</P>",
141 "<P>Abcd ^kl</P>"
142 };
143
144 static final String INSERT2="<P>Abcd efgh XY blah ijkl</P>";
145 static final String INSERTED_TEXT = "INSERTED TEXT";
146
147 static final String [] rangeInsertResult = {
148 "<P>Abcd efgh INSERTED TEXTXY blah ijkl</P>",
149 "<P>Abcd efgh XINSERTED TEXTY blah ijkl</P>",
150 "<P>Abcd efgh XYINSERTED TEXT blah ijkl</P>",
151 "<P>Abcd efgh XY blahINSERTED TEXT ijkl</P>"
152 };
153
154
155 public static void main(String args[]) {
156 // is there anything to do?
157 if ( args.length == 0 ) {
158 printUsage();
159 System.exit(1);
160 }
161 new Test(args[0]);
162 }
163
164 /** Prints the usage. */
165 private static void printUsage() {
166
167 System.err.println("usage: java dom.range.Test (options) ...");
168 System.err.println();
169 System.err.println("options:");
170 System.err.println(" all all tests");
171 System.err.println(" delete delete test");
172 System.err.println(" extract extract test");
173 System.err.println(" clone clone test");
174 System.err.println(" insert insert test");
175 System.err.println(" surround surround test");
176 System.err.println(" insert2 insert mutation test");
177 System.err.println(" delete2 delete mutation test");
178
179 } // printUsage()
180
181
182 public Test(String arg) {
183 if (arg.equals("all")) {
184 boolean all = false;
185 all = performTest("delete");
186 all = performTest("extract")&&all;
187 all = performTest("clone")&&all;
188 all = performTest("insert")&&all;
189 all = performTest("surround")&&all;
190 all = performTest("insert2")&&all;
191 all = performTest("delete2")&&all;
192 if (all)
193 System.out.println("*** ALL TESTS PASSED! ***");
194 else
195 System.out.println("*** ONE OR MORE TESTS FAILED! ***");
196
197 } else {
198 performTest(arg);
199 }
200 }
201
202 public boolean performTest(String arg) {
203 boolean passed = true;
204 try {
205 DOMWriter writer = new DOMWriter(false);
206 DOMParser parser = new DOMParser();
207 if (!arg.equals("delete2") && !arg.equals("insert2")) {
208 System.out.println("\n*************** Test == "+arg+" ***************");
209 for (int i = 0; i < tests.length; i++) {
210 System.out.println("\n\nTest["+i+"]");
211 System.out.println("\nBefore "+arg+": document="+tests[i]+":");
212 parser.parse(new InputSource(new StringReader(tests[i])));
213 DocumentImpl document = (DocumentImpl)parser.getDocument();
214 Range range = document.createRange();
215 Node root = document.getDocumentElement();
216 boolean surround = false;
217 Node surroundNode=document.createElement(SURROUND);
218 if (arg.equals("surround")) {
219 surround = true;
220 }
221
222 if (i == 0) {
223 range.setStart(root.getFirstChild(), 1);
224 range.setEndBefore(root.getLastChild());
225 if (surround)
226 range.setEnd(root.getLastChild(),1);
227
228 }
229 else if (i == 1) {
230 Node n1 = root.getFirstChild().getNextSibling().
231 getFirstChild();
232 range.setStart(n1, 1);
233 range.setEnd(root.getLastChild(), 1);
234 if (surround)
235 range.setEnd(n1,2);
236 }
237 else if (i == 2) {
238 range.setStart(root.getFirstChild(), 1);
239 Node n2 = root.getFirstChild().getNextSibling().getFirstChild();
240 range.setEnd(n2, 1);
241 if (surround)
242 range.setEndBefore(root.getLastChild());
243 }
244 else if (i == 3) {
245 Node n3 = root.getFirstChild().getFirstChild();
246 range.setStart(n3, 1);
247 range.setEnd(root.getLastChild().getFirstChild(), 1);
248 if (surround) {
249 range.selectNode(root.getFirstChild().getNextSibling());
250 }
251 }
252 else if (i == 4) {
253 Node n4 = root.getFirstChild().getFirstChild().getNextSibling().getFirstChild();
254 range.setStartAfter(n4);
255 range.setEndAfter(root.getLastChild().getFirstChild());
256 if (surround) {
257 range.selectNodeContents(root.getFirstChild().getNextSibling());
258 }
259 }
260
261 System.out.println("range.toString="+range.toString());
262 DocumentFragment frag = null;
263
264 if (arg.equals("surround")) {
265 try {
266 System.out.println("surroundNode="+surroundNode);
267 range.surroundContents(surroundNode);
268 } catch (org.w3c.dom.range.RangeException e) {
269 System.out.println(e);
270 }
271 String result = toString(document);
272 System.out.println("After surround: document="+result+":");
273 if (!result.equals(surroundResult[i])) {
274 System.out.println("Should be: document="+surroundResult[i]+":");
275 passed = false;
276 System.out.println("Test FAILED!");
277 System.out.println("*** Surround document Test["+i+"] FAILED!");
278 }
279 }
280
281 if (arg.equals("insert")) {
282 range.insertNode(document.createTextNode(INSERT));
283 String result = toString(document);
284 System.out.println("After insert: document="+result+":");
285 if (!result.equals(insertResult[i])) {
286 System.out.println("Should be: document="+insertResult[i]+":");
287 passed = false;
288 System.out.println("Test FAILED!");
289 System.out.println("*** Insert document Test["+i+"] FAILED!");
290 }
291
292 } else
293 if (arg.equals("delete")) {
294 range.deleteContents();
295 String result = toString(document);
296 System.out.println("After delete:"+result+":");
297 if (!result.equals(deleteResult[i])) {
298 System.out.println("Should be: document="+deleteResult[i]+":");
299 passed = false;
300 System.out.println("Test FAILED!");
301 System.out.println("*** Delete document Test["+i+"] FAILED!");
302 }
303 }
304 else
305 if (arg.equals("extract")) {
306 frag = range.extractContents();
307 //range.insertNode(document.createTextNode("^"));
308 String result = toString(document);
309 System.out.println("After extract: document="+result+":");
310 if (!result.equals(deleteResult[i])) {
311 System.out.println("Should be: document="+deleteResult[i]+":");
312 passed = false;
313 System.out.println("*** Extract document Test["+i+"] FAILED!");
314 }
315 String fragResult = toString(frag);
316 System.out.println("After extract: fragment="+fragResult+":");
317 if (!fragResult.equals(extractResult[i])) {
318 System.out.println("Should be: fragment="+extractResult[i]+":");
319 passed = false;
320 System.out.println("*** Extract Fragment Test["+i+"] FAILED!");
321 }
322 }
323
324 else
325 if (arg.equals("clone")) {
326 frag = range.cloneContents();
327 String fragResult = toString(frag);
328 System.out.println("After clone: fragment="+fragResult);
329 if (!fragResult.equals(extractResult[i])) {
330 System.out.println("Should be: fragment="+extractResult[i]+":");
331 passed = false;
332 System.out.println("*** Clone Fragment Test["+i+"] FAILED!");
333 }
334 }
335
336 }
337
338 } else
339 if (arg.equals("insert2")) {
340 System.out.println("\n*************** Test == "+arg+" ***************");
341 for (int i = 0; i < 4; i++) {
342
343 System.out.println("\n\nTest["+i+"]");
344 System.out.println("\nBefore "+arg+": document="+INSERT2+":");
345 parser.parse(new InputSource(new StringReader(INSERT2)));
346 DocumentImpl document = (DocumentImpl)parser.getDocument();
347 Node root = document.getDocumentElement();
348 Range range = document.createRange();
349 range.setStart(root.getFirstChild(),11);
350 range.setEnd(root.getFirstChild(),18);
351 Range rangei = document.createRange();
352 if (i == 0) {
353 rangei.setStart(root.getFirstChild(), 10);
354 rangei.setEnd(root.getFirstChild(), 10);
355 }
356 if (i == 1) {
357 rangei.setStart(root.getFirstChild(), 11);
358 rangei.setEnd(root.getFirstChild(), 11);
359 }
360 if (i == 2) {
361 rangei.setStart(root.getFirstChild(), 12);
362 rangei.setEnd(root.getFirstChild(), 12);
363 }
364 if (i == 3) {
365 rangei.setStart(root.getFirstChild(), 17);
366 rangei.setEnd(root.getFirstChild(), 17);
367 }
368 //System.out.println("range: start1=="+range.getStartContainer());
369 //root.insertBefore(document.createTextNode("YES!"), root.getFirstChild());
370 //System.out.println("range: start2=="+range.getStartContainer());
371
372 if (DEBUG) System.out.println("before insert start="+range.getStartOffset());
373 if (DEBUG) System.out.println("before insert end="+range.getEndOffset());
374 rangei.insertNode(document.createTextNode(INSERTED_TEXT));
375 if (DEBUG) System.out.println("after insert start="+range.getStartOffset());
376 if (DEBUG) System.out.println("after insert end="+range.getEndOffset());
377
378 String result = toString(document);
379 System.out.println("After insert2: document="+result+":");
380 if (!result.equals(rangeInsertResult[i])) {
381 System.out.println("Should be: document="+rangeInsertResult[i]+":");
382 passed = false;
383 System.out.println("Test FAILED!");
384 System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
385 }
386 }
387 } else
388 if (arg.equals("delete2")) {
389 //
390 // Range Deletion, acting upon another range.
391 //
392
393 System.out.println("\n*************** Test == "+arg+" ***************");
394 for (int i = 0; i < rangeDelete.length; i++) {
395 System.out.println("\n\nTest["+i+"]");
396 System.out.println("\nBefore "+arg+": document="+rangeDelete[i]+":");
397 parser.parse(new InputSource(new StringReader(rangeDelete[i])));
398 DocumentImpl document = (DocumentImpl)parser.getDocument();
399 Range range = document.createRange();
400 Range ranged = document.createRange();
401 Node root = document.getDocumentElement();
402 boolean surround = false;
403 Node surroundNode=document.createElement(SURROUND);
404 if (arg.equals("surround")) {
405 surround = true;
406 }
407
408 if (i == 0) {
409 ranged.setStart(root.getFirstChild(), 5);
410 ranged.setEnd(root.getFirstChild(), 14);
411
412 range.setStart(root.getFirstChild(), 11);
413 range.setEnd(root.getFirstChild(), 19);
414 }
415 else if (i == 1) {
416 ranged.setStart(root.getFirstChild(), 5);
417 ranged.setEnd(root.getFirstChild(), 22);
418
419 range.setStart(root.getFirstChild(), 11);
420 range.setEnd(root.getFirstChild(), 21);
421 }
422 else if (i == 2) {
423 ranged.setStart(root.getFirstChild(), 5);
424 ranged.setEnd(root.getFirstChild().getNextSibling()
425 .getFirstChild(), 1);
426
427 range.setStart(root.getFirstChild(), 11);
428
429 range.setEndAfter(root.getFirstChild().getNextSibling()
430 .getFirstChild());
431 }
432 else if (i == 3) {
433 ranged.setStart(root.getFirstChild(), 5);
434 ranged.setEnd(root.getFirstChild(), 11);
435
436 range.setStart(root.getFirstChild(), 11);
437 range.setEnd(root.getFirstChild(), 21);
438 }
439 else if (i == 4) {
440 ranged.selectNode(root.getFirstChild().getNextSibling());
441
442 range.setStart(root.getFirstChild().getNextSibling()
443 .getFirstChild(), 6);
444 range.setEnd(root.getFirstChild().getNextSibling()
445 .getFirstChild(), 15);
446 }
447
448 DocumentFragment frag = null;
449
450 if (arg.equals("delete2")) {
451 if (DEBUG) {
452 System.out.println("BEFORE deleteContents()");
453 System.out.println("ranged: startc="+ranged.getStartContainer());
454 System.out.println("ranged: starto="+ranged.getStartOffset());
455 System.out.println("ranged: endc="+ranged.getEndContainer());
456 System.out.println("ranged: endo="+ranged.getEndOffset());
457
458 System.out.println("range: startc="+range.getStartContainer());
459 System.out.println("range: starto="+range.getStartOffset());
460 System.out.println("range: endc="+range.getEndContainer());
461 System.out.println("range: endo="+range.getEndOffset());
462 }
463 ranged.deleteContents();
464 String result = null;
465 if (DEBUG) {
466 System.out.println("AFTER deleteContents()");
467 result = toString(document);
468 System.out.println("ranged: startc="+ranged.getStartContainer());
469 System.out.println("ranged: starto="+ranged.getStartOffset());
470 System.out.println("ranged: endc="+ranged.getEndContainer());
471 System.out.println("ranged: endo="+ranged.getEndOffset());
472
473 System.out.println("range: startc="+range.getStartContainer());
474 System.out.println("range: starto="+range.getStartOffset());
475 System.out.println("range: endc="+range.getEndContainer());
476 System.out.println("range: endo="+range.getEndOffset());
477 }
478
479 ranged.insertNode(document.createTextNode("^"));
480
481 result = toString(document);
482 System.out.println("After delete2: document="+result+":");
483 if (!result.equals(rangeDeleteResult[i])) {
484 System.out.println("Should be: document="+rangeDeleteResult[i]+":");
485 passed = false;
486 System.out.println("Test FAILED!");
487 System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
488 }
489 }
490 }
491
492 }
493
494
495 }
496 catch (org.xml.sax.SAXParseException spe) {
497 passed = false;
498 }
499 catch (org.xml.sax.SAXException se) {
500 if (se.getException() != null)
501 se.getException().printStackTrace(System.err);
502 else
503 se.printStackTrace(System.err);
504 passed = false;
505 }
506 catch (Exception e) {
507 e.printStackTrace(System.err);
508 passed = false;
509 }
510 if (!passed) System.out.println("*** The "+arg+" Test FAILED! ***");
511
512 return passed;
513 }
514 StringBuffer sb;
515 boolean canonical = true;
516
517 String toString(Node node) {
518 sb = new StringBuffer();
519 return print(node);
520
521 }
522
523 /** Prints the specified node, recursively. */
524 public String print(Node node) {
525
526 // is there anything to do?
527 if ( node == null ) {
528 return sb.toString();
529 }
530
531 int type = node.getNodeType();
532 switch ( type ) {
533 // print document
534 case Node.DOCUMENT_NODE: {
535 return print(((Document)node).getDocumentElement());
536 //out.flush();
537 //break;
538 }
539
540 // print element with attributes
541 case Node.ELEMENT_NODE: {
542 sb.append('<');
543 sb.append(node.getNodeName());
544 Attr attrs[] = sortAttributes(node.getAttributes());
545 for ( int i = 0; i < attrs.length; i++ ) {
546 Attr attr = attrs[i];
547 sb.append(' ');
548 sb.append(attr.getNodeName());
549 sb.append("=\"");
550 sb.append(normalize(attr.getNodeValue()));
551 sb.append('"');
552 }
553 sb.append('>');
554 NodeList children = node.getChildNodes();
555 if ( children != null ) {
556 int len = children.getLength();
557 for ( int i = 0; i < len; i++ ) {
558 print(children.item(i));
559 }
560 }
561 break;
562 }
563
564 // handle entity reference nodes
565 case Node.ENTITY_REFERENCE_NODE: {
566 if ( canonical ) {
567 NodeList children = node.getChildNodes();
568 if ( children != null ) {
569 int len = children.getLength();
570 for ( int i = 0; i < len; i++ ) {
571 print(children.item(i));
572 }
573 }
574 } else {
575 sb.append('&');
576 sb.append(node.getNodeName());
577 sb.append(';');
578 }
579 break;
580 }
581
582 // print cdata sections
583 case Node.CDATA_SECTION_NODE: {
584 if ( canonical ) {
585 sb.append(normalize(node.getNodeValue()));
586 } else {
587 sb.append("<![CDATA[");
588 sb.append(node.getNodeValue());
589 sb.append("]]>");
590 }
591 break;
592 }
593
594 // print text
595 case Node.TEXT_NODE: {
596 sb.append(normalize(node.getNodeValue()));
597 break;
598 }
599
600 // print processing instruction
601 case Node.PROCESSING_INSTRUCTION_NODE: {
602 sb.append("<?");
603 sb.append(node.getNodeName());
604 String data = node.getNodeValue();
605 if ( data != null && data.length() > 0 ) {
606 sb.append(' ');
607 sb.append(data);
608 }
609 sb.append("?>");
610 break;
611 }
612 // handle entity reference nodes
613 case Node.DOCUMENT_FRAGMENT_NODE: {
614 NodeList children = node.getChildNodes();
615 if ( children != null ) {
616 int len = children.getLength();
617 for ( int i = 0; i < len; i++ ) {
618 print(children.item(i));
619 }
620 }
621 break;
622 }
623 }
624
625 if ( type == Node.ELEMENT_NODE ) {
626 sb.append("</");
627 sb.append(node.getNodeName());
628 sb.append('>');
629 }
630
631 return sb.toString();
632
633 } // print(Node)
634
635 /** Returns a sorted list of attributes. */
636 protected Attr[] sortAttributes(NamedNodeMap attrs) {
637
638 int len = (attrs != null) ? attrs.getLength() : 0;
639 Attr array[] = new Attr[len];
640 for ( int i = 0; i < len; i++ ) {
641 array[i] = (Attr)attrs.item(i);
642 }
643 for ( int i = 0; i < len - 1; i++ ) {
644 String name = array[i].getNodeName();
645 int index = i;
646 for ( int j = i + 1; j < len; j++ ) {
647 String curName = array[j].getNodeName();
648 if ( curName.compareTo(name) < 0 ) {
649 name = curName;
650 index = j;
651 }
652 }
653 if ( index != i ) {
654 Attr temp = array[i];
655 array[i] = array[index];
656 array[index] = temp;
657 }
658 }
659
660 return (array);
661
662 } // sortAttributes(NamedNodeMap):Attr[]
663
664 /** Normalizes the given string. */
665 protected String normalize(String s) {
666 StringBuffer str = new StringBuffer();
667
668 int len = (s != null) ? s.length() : 0;
669 for ( int i = 0; i < len; i++ ) {
670 char ch = s.charAt(i);
671 switch ( ch ) {
672 case '<': {
673 str.append("<");
674 break;
675 }
676 case '>': {
677 str.append(">");
678 break;
679 }
680 case '&': {
681 str.append("&");
682 break;
683 }
684 case '"': {
685 str.append(""");
686 break;
687 }
688 case '\r':
689 case '\n': {
690 if ( canonical ) {
691 str.append("&#");
692 str.append(Integer.toString(ch));
693 str.append(';');
694 break;
695 }
696 // else, default append char
697 }
698 default: {
699 str.append(ch);
700 }
701 }
702 }
703
704 return (str.toString());
705
706 } // normalize(String):String
707
708
709 }