| 1 21 22 package nu.xom.tests; 23 24 import nu.xom.Node; 25 import nu.xom.Serializer; 26 import nu.xom.Element; 27 import nu.xom.DocType; 28 import nu.xom.Document; 29 import nu.xom.Builder; 30 import nu.xom.Comment; 31 import nu.xom.ParsingException; 32 import nu.xom.ProcessingInstruction; 33 import nu.xom.Attribute; 34 import nu.xom.UnavailableCharacterException; 35 import nu.xom.XMLException; 36 37 import java.io.ByteArrayInputStream ; 38 import java.io.ByteArrayOutputStream ; 39 import java.io.File ; 40 import java.io.IOException ; 41 import java.io.BufferedReader ; 42 import java.io.InputStream ; 43 import java.io.OutputStream ; 44 import java.io.StringReader ; 45 import java.io.UnsupportedEncodingException ; 46 47 56 public class SerializerTest extends XOMTestCase { 57 58 private Builder parser; 59 private final static double version = Double.parseDouble( 60 System.getProperty("java.version").substring(0,3) 61 ); 62 Element root = new Element("root"); 63 Document doc = new Document(root); 64 ByteArrayOutputStream out = new ByteArrayOutputStream (); 65 66 67 public SerializerTest(String name) { 68 super(name); 69 } 70 71 72 protected void setUp() { 73 parser = new Builder(); 74 } 75 76 77 public void testCDATASectionEndDelimiter() throws IOException { 78 79 root.appendChild("]]>"); 80 Serializer serializer = new Serializer(out, "UTF-8"); 81 serializer.setMaxLength(20); 82 serializer.write(doc); 83 String result = out.toString("UTF-8"); 84 assertTrue(result.indexOf("]]>") > 0); 85 86 } 87 88 89 public void testXMLSpacePreserve() throws IOException { 90 91 root.addAttribute( 92 new Attribute( 93 "xml:space", 94 "http://www.w3.org/XML/1998/namespace", 95 "preserve")); 96 String value = 97 "This is a long sentence with plenty of opportunities for " + 98 "breaking from beginning to end."; 99 root.appendChild(value); 100 Serializer serializer = new Serializer(out, "UTF-8"); 101 serializer.setMaxLength(20); 102 serializer.write(doc); 103 String result = out.toString("UTF-8"); 104 assertTrue(result.indexOf(value) > 0); 105 106 } 107 108 109 116 public void testUTF16LEBOM() throws IOException { 117 118 if (version >= 1.3) { 119 Serializer serializer = new Serializer(out, "UTF-16LE"); 121 serializer.write(doc); 122 serializer.flush(); 123 out.flush(); 124 out.close(); 125 byte[] data = out.toByteArray(); 126 assertEquals('<', (char) data[0]); 127 assertEquals((byte) 0, data[1]); 128 } 129 130 } 131 132 133 140 public void testUTF16BOM() throws IOException { 141 142 Serializer serializer = new Serializer(out, "UTF-16"); 143 serializer.write(doc); 144 serializer.flush(); 145 out.flush(); 146 out.close(); 147 byte[] data = out.toByteArray(); 148 assertEquals((byte) 0xFE, data[0]); 149 assertEquals((byte) 0xFF, data[1]); 150 assertEquals((byte) 0, data[2]); 151 assertEquals('<', (char) data[3]); 152 153 } 154 155 156 163 public void testUTF16BEBOM() throws IOException { 164 165 if (version >= 1.3) { 166 Serializer serializer = new Serializer(out, "UTF-16BE"); 168 serializer.write(doc); 169 serializer.flush(); 170 out.flush(); 171 out.close(); 172 byte[] data = out.toByteArray(); 173 assertEquals((byte) 0, data[0]); 174 assertEquals('<', (char) data[1]); 175 } 176 177 } 178 179 180 public void testXMLSpaceDefault() throws IOException { 181 182 root.addAttribute( 183 new Attribute( 184 "xml:space", 185 "http://www.w3.org/XML/1998/namespace", 186 "preserve")); 187 Element child1 = new Element("preserve"); 188 String value = 189 "This is a long sentence with plenty of opportunities for " + 190 "breaking from beginning to end."; 191 child1.appendChild(value); 192 Element child2 = new Element("default"); 193 root.appendChild(child1); 194 root.appendChild(child2); 195 child2.addAttribute( 196 new Attribute( 197 "xml:space", 198 "http://www.w3.org/XML/1998/namespace", 199 "default")); 200 String value2 = 201 "This is another very long sentence with plenty" + 202 " of opportunities for breaking from beginning to end."; 203 child2.appendChild(value2); 204 205 String value3 = 206 "This is still another very long sentence with plenty of " + 207 "opportunities for breaking from beginning to end."; 208 Element preserveAgain = new Element("test"); 209 preserveAgain.appendChild(value3); 210 child2.appendChild(preserveAgain); 211 preserveAgain.addAttribute( 212 new Attribute( 213 "xml:space", 214 "http://www.w3.org/XML/1998/namespace", 215 "preserve")); 216 217 218 Serializer serializer = new Serializer(out, "UTF-8"); 219 serializer.setMaxLength(20); 220 serializer.write(doc); 221 String result = out.toString("UTF-8"); 222 assertTrue(result.indexOf(value) > 0); 223 assertTrue(result.indexOf(value3) > 0); 224 assertEquals(-1, result.indexOf(value2)); 225 226 } 227 228 229 public void testXMLSpacePreserveWithIndenting() 230 throws IOException { 231 232 root.addAttribute( 233 new Attribute( 234 "xml:space", 235 "http://www.w3.org/XML/1998/namespace", 236 "preserve")); 237 root.appendChild(new Element("sameline")); 238 ByteArrayOutputStream out = new ByteArrayOutputStream (); 239 Serializer serializer = new Serializer(out, "UTF-8"); 240 serializer.setIndent(4); 241 serializer.write(doc); 242 String result = out.toString("UTF-8"); 243 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" 244 + "<root xml:space=\"preserve\"><sameline/></root>\r\n", 245 result); 246 247 } 248 249 250 public void testXMLSpaceUnspecifiedValueWithIndenting() 251 throws IOException { 252 253 root.addAttribute( 254 new Attribute( 255 "xml:space", 256 "http://www.w3.org/XML/1998/namespace", 257 "undefined")); 258 root.appendChild(new Element("sameline")); 259 Serializer serializer = new Serializer(out, "UTF-8"); 260 serializer.setIndent(4); 261 serializer.write(doc); 262 String result = out.toString("UTF-8"); 263 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" 264 + "<root xml:space=\"undefined\">\r\n <sameline/>\r\n</root>\r\n", 265 result); 266 267 } 268 269 270 public void testXMLSpaceDefaultWithIndenting() throws IOException { 271 272 root.addAttribute( 273 new Attribute( 274 "xml:space", 275 "http://www.w3.org/XML/1998/namespace", 276 "preserve")); 277 Element child = new Element("child"); 278 child.addAttribute( 279 new Attribute( 280 "xml:space", 281 "http://www.w3.org/XML/1998/namespace", 282 "default")); 283 root.appendChild(child); 284 Serializer serializer = new Serializer(out, "UTF-8"); 285 serializer.setIndent(4); 286 serializer.write(doc); 287 String result = out.toString("UTF-8"); 288 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" 289 + "<root xml:space=\"preserve\">" + 290 "<child xml:space=\"default\"/></root>\r\n", 291 result); 292 293 } 294 295 296 public void testXMLSpaceDefaultWithIndentingAndGrandchildren() 297 throws IOException { 298 299 root.addAttribute( 300 new Attribute( 301 "xml:space", 302 "http://www.w3.org/XML/1998/namespace", 303 "preserve")); 304 Element child = new Element("child"); 305 child.addAttribute( 306 new Attribute( 307 "xml:space", 308 "http://www.w3.org/XML/1998/namespace", 309 "default")); 310 root.appendChild(child); 311 child.appendChild(new Element("differentLine")); 312 Serializer serializer = new Serializer(out, "UTF-8"); 313 serializer.setIndent(2); 314 serializer.write(doc); 315 String result = out.toString("UTF-8"); 316 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" 317 + "<root xml:space=\"preserve\">" + 318 "<child xml:space=\"default\">\r\n <differentLine/>\r\n" + 319 " </child></root>\r\n", 320 result); 321 322 } 323 324 325 public void testDontSerializeXMLNamespace() throws IOException { 326 327 Element root 328 = new Element("html", "http://www.w3.org/1999/xhtml"); 329 root.addAttribute( 330 new Attribute( 331 "xml:lang", "http://www.w3.org/XML/1998/namespace", "en")); 332 Document doc = new Document(root); 333 Serializer serializer = new Serializer(out, "UTF-8"); 334 serializer.write(doc); 335 String result = out.toString("UTF-8"); 336 assertEquals(-1, result.indexOf("xmlns:xml")); 337 assertTrue(result.indexOf("xml:lang=") > 1); 338 339 } 340 341 public void testDontSerializeNoNamespace() throws IOException { 342 343 Serializer serializer = new Serializer(out, "UTF-8"); 344 serializer.write(doc); 345 String result = out.toString("UTF-8"); 346 assertEquals(-1, result.indexOf("xmlns=")); 347 348 } 349 350 351 public void testDefaultNamespace() throws IOException { 352 353 Element root = new Element("root", "http://www.example.com"); 354 Document doc = new Document(root); 355 Serializer serializer = new Serializer(out, "UTF-8"); 356 serializer.write(doc); 357 String result = out.toString("UTF-8"); 358 assertTrue(result.indexOf("xmlns=") > 1); 359 assertTrue(result.indexOf("http://www.example.com") > 1); 360 361 } 362 363 364 public void testEmptyElement() throws IOException { 365 366 Serializer serializer = new Serializer(out, "UTF-8"); 367 serializer.write(doc); 368 String result = out.toString("UTF-8"); 369 assertEquals( 370 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<root/>\r\n", 371 result 372 ); 373 374 } 375 376 377 public void testElementWithText() throws IOException { 378 379 String data = " test \n\n \n \n hello again"; 380 root.appendChild(data); 381 Serializer serializer = new Serializer(out, "UTF-8"); 382 serializer.write(doc); 383 String result = out.toString("UTF-8"); 384 385 assertEquals( 386 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<root>" 387 + data + "</root>\r\n", 388 result); 389 390 } 391 392 393 public void testStaticElementWithText() 394 throws IOException { 395 396 String data = " test \n\n \n \n hello again"; 397 root.appendChild(data); 398 Serializer serializer = new Serializer(out); 399 serializer.write(doc); 400 String result = out.toString("UTF-8"); 401 402 assertEquals( 403 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<root>" 404 + data + "</root>\r\n", 405 result); 406 407 } 408 409 410 public void testElementWithTextAndCarriageReturns() 411 throws IOException { 412 413 String data = " test \r\n \n \r hello again"; 414 root.appendChild(data); 415 Serializer serializer = new Serializer(out, "UTF-8"); 416 serializer.write(doc); 417 String result = out.toString("UTF-8"); 418 419 assertEquals( 420 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<root>" 421 + " test 
\n \n 
 hello again" 422 + "</root>\r\n", 423 result); 424 425 } 426 427 428 private void serializeParseAndCompare(Document doc) 429 throws IOException , ParsingException { 430 431 ByteArrayOutputStream out = new ByteArrayOutputStream (); 432 Serializer serializer = new Serializer(out, "UTF-8"); 433 serializer.write(doc); 434 String result = out.toString("UTF-8"); 435 436 Document resultDoc = parser.build(result, null); 437 XOMTestCase.assertEquals(doc, resultDoc); 438 439 setOutputStreamSerializeParseAndCompare(doc); 440 441 } 442 443 444 private void setOutputStreamSerializeParseAndCompare(Document doc) 445 throws IOException , ParsingException { 446 447 Serializer serializer = new Serializer(out); 448 serializer.write(doc); 449 ByteArrayOutputStream out2 = new ByteArrayOutputStream (); 450 serializer.setOutputStream(out2); 451 serializer.write(doc); 452 String result = out2.toString("UTF-8"); 453 454 Document resultDoc = parser.build(result, null); 455 XOMTestCase.assertEquals(doc, resultDoc); 456 457 } 458 459 460 public void testComment() 461 throws IOException , ParsingException { 462 463 String data = " <>&&entity; test \n hello again"; 464 root.appendChild(new Comment(data)); 465 serializeParseAndCompare(doc); 466 467 } 468 469 470 public void testProcessingInstruction() 471 throws IOException , ParsingException { 472 473 String data = "<>&&entity; test \n hello again"; 474 root.appendChild(new ProcessingInstruction("target", data)); 475 serializeParseAndCompare(doc); 476 477 } 478 479 public void testBasicElementWithText() 480 throws IOException , ParsingException { 481 482 String data = " test \n hello again"; 483 root.appendChild(data); 484 serializeParseAndCompare(doc); 485 486 } 487 488 489 public void testAttributes() 490 throws IOException , ParsingException { 491 492 root.addAttribute(new Attribute("test", "sadlkhasdk")); 493 String data = " test \n hello again"; 494 root.appendChild(data); 495 serializeParseAndCompare(doc); 496 497 root.addAttribute(new Attribute("test2", "sadlkhasdk")); 498 serializeParseAndCompare(doc); 499 500 root.addAttribute(new Attribute("test3", " s adl khasdk ")); 501 serializeParseAndCompare(doc); 502 503 root.addAttribute(new Attribute("xlink:type", 504 "http://www.w3.org/2001/xlink", " s adl khasdk ")); 505 serializeParseAndCompare(doc); 506 507 } 508 509 510 public void testChildElements() 511 throws IOException , ParsingException { 512 513 serializeParseAndCompare(doc); 514 515 Element child1 = new Element("child"); 516 Element child2 = new Element("child"); 517 Element child3 = new Element("child"); 518 serializeParseAndCompare(doc); 519 root.appendChild(child1); 520 serializeParseAndCompare(doc); 521 child1.appendChild(child2); 522 serializeParseAndCompare(doc); 523 root.appendChild(child3); 524 serializeParseAndCompare(doc); 525 child3.appendChild("some data"); 526 serializeParseAndCompare(doc); 527 child2.appendChild("\nsome data with \n line breaks\n"); 528 serializeParseAndCompare(doc); 529 root.insertChild("now let's have some mixed content", 0); 530 serializeParseAndCompare(doc); 531 532 root.setNamespaceURI("http://www.example.org/"); 533 serializeParseAndCompare(doc); 534 child1.setNamespaceURI("http://www.example.org/"); 535 serializeParseAndCompare(doc); 536 child2.setNamespaceURI("http://www.example.org/"); 537 serializeParseAndCompare(doc); 538 child3.setNamespaceURI("http://www.example.org/"); 539 serializeParseAndCompare(doc); 540 child1.setNamespacePrefix("example"); 541 serializeParseAndCompare(doc); 542 child2.setNamespacePrefix("perverse"); 543 serializeParseAndCompare(doc); 544 545 } 546 547 548 public void testPrologAndEpilog() 549 throws IOException , ParsingException { 550 551 serializeParseAndCompare(doc); 552 553 doc.insertChild(new Comment("Hello"), 0); 554 serializeParseAndCompare(doc); 555 doc.insertChild(new DocType("root"), 0); 556 serializeParseAndCompare(doc); 557 doc.insertChild(new ProcessingInstruction("test", "some data"), 558 0); 559 serializeParseAndCompare(doc); 560 doc.insertChild(new Comment("Goodbye"), 0); 561 serializeParseAndCompare(doc); 562 doc.insertChild( 563 new ProcessingInstruction("goodbye", "some data"), 0); 564 serializeParseAndCompare(doc); 565 doc.appendChild(new Comment("Hello")); 566 serializeParseAndCompare(doc); 567 doc.appendChild( 568 new ProcessingInstruction("test", "some data")); 569 serializeParseAndCompare(doc); 570 571 } 572 573 574 public void testChangeLineSeparator() throws IOException { 575 576 String breaks = 577 "This\nstring\rcontains\r\nseveral\r\rweird line breaks."; 578 root.appendChild(breaks); 579 root.addAttribute(new Attribute("test", breaks)); 580 581 Serializer serializer = new Serializer(out, "UTF-8"); 582 serializer.setLineSeparator("\n"); 583 serializer.write(doc); 584 String result = out.toString("UTF-8"); 585 assertTrue(result.indexOf('\n') > 0); 586 assertTrue(result + "**\n" + result.indexOf('\r'), 587 result.indexOf('\r') == -1); 588 589 out = new ByteArrayOutputStream (); 590 serializer = new Serializer(out, "UTF-8"); 591 serializer.setLineSeparator("\r"); 592 serializer.write(doc); 593 result = out.toString("UTF-8"); 594 assertTrue(result.indexOf('\r') > 0); 595 assertTrue(result.indexOf('\n') == -1); 596 597 out = new ByteArrayOutputStream (); 598 serializer = new Serializer(out, "UTF-8"); 599 serializer.setLineSeparator("\r\n"); 600 serializer.write(doc); 601 result = out.toString("UTF-8"); 602 assertTrue(result.indexOf("\r\n") > 0); 603 for (int i = 0; i < result.length(); i++) { 604 int c = result.charAt(i); 605 if (c == '\r') assertTrue(result.charAt(i+1) == '\n'); 606 } 607 608 } 609 610 611 public void testDontChangeLineSeparator() throws IOException { 612 613 String breaks 614 = "This\nstring\rcontains\r\rseveral\n\nweird line breaks."; 615 String breaksHalfEscaped 616 = "This\nstring
contains

several" + 617 "\n\nweird line breaks."; 618 String breaksEscaped 619 = "This
string
contains

several" + 620 "

weird line breaks."; 621 root.appendChild(breaks); 622 623 Serializer serializer = new Serializer(out, "UTF-8"); 624 serializer.write(doc); 625 String result = out.toString("UTF-8"); 626 assertTrue(result.indexOf(breaksHalfEscaped) > 0); 627 628 root = new Element("root"); 629 doc = new Document(root); 630 root.addAttribute(new Attribute("test", breaks)); 631 632 out = new ByteArrayOutputStream (); 633 serializer = new Serializer(out, "UTF-8"); 634 serializer.write(doc); 635 result = out.toString("UTF-8"); 636 assertTrue(result.indexOf(breaksEscaped) > 0); 637 638 } 639 640 641 public void testPreserveBaseURI() throws IOException { 642 643 Serializer serializer = new Serializer(out, "UTF-8"); 644 serializer.setPreserveBaseURI(true); 645 serializer.write(doc); 646 String result = out.toString("UTF-8"); 647 assertTrue(result.indexOf("<root") > 1); 648 doc.setBaseURI("http://www.example.com/index.xml"); 649 serializer.write(doc); 650 result = out.toString("UTF-8"); 651 assertTrue(result.indexOf("<root ") > 1); 652 assertTrue(result.indexOf("xml:base=") > 1); 653 assertTrue( 654 result.indexOf("http://www.example.com/index.xml") > 1 655 ); 656 657 } 658 659 660 public void testPreserveBaseURIWithChildren() throws IOException { 661 662 String base = "http://www.example.com/index.xml"; 663 root.setBaseURI(base); 664 Element child = new Element("child"); 665 child.setBaseURI(base); 666 root.appendChild(child); 667 Serializer serializer = new Serializer(out, "UTF-8"); 668 serializer.setPreserveBaseURI(true); 669 serializer.write(doc); 670 String result = out.toString("UTF-8"); 671 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" 672 + "<root xml:base=\"" + base + "\"><child/></root>\r\n", result); 673 674 } 675 676 677 public void testPreserveBaseURIDoesntOverrideXMLBase() 678 throws IOException { 679 680 root.addAttribute(new Attribute("xml:base", 681 "http://www.w3.org/XML/1998/namespace", 682 "http://www.cafeconleche.org/")); 683 Serializer serializer = new Serializer(out, "UTF-8"); 684 serializer.setPreserveBaseURI(true); 685 serializer.write(doc); 686 String result = out.toString("UTF-8"); 687 assertTrue(result.indexOf("<root") > 1); 688 doc.setBaseURI("http://www.example.com/index.xml"); 689 serializer.write(doc); 690 result = out.toString("UTF-8"); 691 assertTrue(result.indexOf("<root ") > 1); 692 assertTrue(result.indexOf("xml:base=") > 1); 693 assertTrue(result.indexOf("http://www.cafeconleche.org/") > 1); 694 assertEquals(-1, result.indexOf("http://www.example.com/index.xml")); 695 696 } 697 698 699 public void testSetLineSeparator() { 700 701 Serializer serializer = new Serializer(System.out); 702 703 serializer.setLineSeparator("\r"); 704 assertEquals("\r", serializer.getLineSeparator()); 705 serializer.setLineSeparator("\n"); 706 assertEquals("\n", serializer.getLineSeparator()); 707 serializer.setLineSeparator("\r\n"); 708 assertEquals("\r\n", serializer.getLineSeparator()); 709 710 try { 711 serializer.setLineSeparator("r"); 712 fail("Allowed illegal separator character"); 713 } 714 catch (IllegalArgumentException success) { 715 assertNotNull(success.getMessage()); 716 } 717 718 try { 719 serializer.setLineSeparator("n"); 720 fail("Allowed illegal separator character"); 721 } 722 catch (IllegalArgumentException success) { 723 assertNotNull(success.getMessage()); 724 } 725 726 try { 727 serializer.setLineSeparator(" "); 728 fail("Allowed illegal separator character"); 729 } 730 catch (IllegalArgumentException success) { 731 assertNotNull(success.getMessage()); 732 } 733 734 try { 735 serializer.setLineSeparator("rn"); 736 fail("Allowed illegal separator character"); 737 } 738 catch (IllegalArgumentException success) { 739 assertNotNull(success.getMessage()); 740 } 741 742 try { 743 serializer.setLineSeparator("<"); 744 fail("Allowed illegal separator character"); 745 } 746 catch (IllegalArgumentException success) { 747 assertNotNull(success.getMessage()); 748 } 749 750 try { 751 serializer.setLineSeparator("\u0085"); 752 fail("Allowed NEL separator character"); 753 } 754 catch (IllegalArgumentException success) { 755 assertNotNull(success.getMessage()); 756 } 757 758 } 759 760 761 public void testLowerLimitOfUnicodeInCharacterData() 762 throws IOException { 763 764 root.appendChild("\uD800\uDC00"); 765 Serializer serializer = new Serializer(out, "ISO-8859-1"); 766 serializer.write(doc); 767 String result = out.toString("ISO-8859-1"); 768 assertTrue(result, result.indexOf("𐀀") > 12); 769 770 } 771 772 773 public void testUpperLimitOfUnicodeInCharacterData() 774 throws IOException { 775 776 root.appendChild("\uDBFF\uDFFD"); 777 Serializer serializer = new Serializer(out, "ISO-8859-1"); 778 serializer.write(doc); 779 String result = out.toString("ISO-8859-1"); 780 assertTrue(result, result.indexOf("􏿽") > 12); 781 782 } 783 784 785 public void testSerializePlane1CharacterInAttributeValue() 786 throws IOException { 787 788 |