| 1 21 22 package nu.xom.tests; 23 24 import java.io.File ; 25 import java.io.IOException ; 26 import nu.xom.ParsingException; 27 28 import nu.xom.Attribute; 29 import nu.xom.Builder; 30 import nu.xom.Comment; 31 import nu.xom.DocType; 32 import nu.xom.Document; 33 import nu.xom.Element; 34 import nu.xom.Node; 35 import nu.xom.NodeFactory; 36 import nu.xom.Nodes; 37 import nu.xom.ProcessingInstruction; 38 import nu.xom.Text; 39 import nu.xom.ValidityException; 40 import nu.xom.XMLException; 41 42 52 public class NodeFactoryTest extends XOMTestCase { 53 54 55 private File data = new File ("data"); 56 57 58 public NodeFactoryTest(String name) { 59 super(name); 60 } 61 62 63 protected void setUp() { 64 numNodesInExternalDTDSubset = 0; 65 } 66 67 68 public void testSkippingComment() 69 throws IOException , ParsingException { 70 71 String data = "<a>1<!--tetetwkfjkl-->8</a>"; 72 Builder builder = new Builder(new CommentFilter()); 73 Document doc = builder.build(data, "http://www.example.org/"); 74 Element root = doc.getRootElement(); 75 assertEquals("Skipped comment interrupted text node", 76 2, root.getChildCount()); 77 assertEquals("18", doc.getValue()); 78 Node first = root.getChild(0); 79 assertEquals(first.getValue(), "1"); 80 Node second = root.getChild(1); 81 assertEquals(second.getValue(), "8"); 82 83 } 84 85 86 static class CommentFilter extends NodeFactory { 87 88 public Nodes makeComment(String data) { 89 return new Nodes(); 90 } 91 92 } 93 94 95 public void testCantAddOneElementMultipleTimes() 96 throws IOException , ParsingException { 97 98 String data = "<a><b>18</b></a>"; 99 Builder builder = new Builder(new SingleElementFactory()); 100 try { 101 builder.build(data, "http://www.example.org/"); 102 fail("Allowed one element in several places"); 103 } 104 catch (ParsingException success) { 105 assertNotNull(success.getMessage()); 106 } 107 108 } 109 110 111 public void testCantAddOneAttributeMultipleTimes() 112 throws IOException , ParsingException { 113 114 String data = "<a test=\"value\" name=\"data\"></a>"; 115 Builder builder = new Builder(new SingleAttributeFactory()); 116 try { 117 builder.build(data, "http://www.example.org/"); 118 fail("Allowed one attribute twice"); 119 } 120 catch (ParsingException success) { 121 assertNotNull(success.getMessage()); 122 } 123 124 } 125 126 127 private static class SingleElementFactory extends NodeFactory { 128 129 private Element test = new Element("test"); 130 131 public Element startMakingElement(String name, String namespace) { 132 return test; 133 } 134 135 } 136 137 138 private static class SingleAttributeFactory extends NodeFactory { 139 140 private Attribute test = new Attribute("limit", "none"); 141 142 public Nodes makeAttribute(String name, String URI, 143 String value, Attribute.Type type) { 144 return new Nodes(test); 145 } 146 147 } 148 149 150 public void testChangingElementName() 151 throws IOException , ParsingException { 152 153 String data 154 = "<a>1<b>2<a>3<b>4<a>innermost</a>5</b>6</a>7</b>8</a>"; 155 Builder builder = new Builder(new CFactory()); 156 Document doc = builder.build(data, "http://www.example.org/"); 157 Element root = doc.getRootElement(); 158 assertEquals("1234innermost5678", doc.getValue()); 159 assertEquals("c", root.getQualifiedName()); 160 assertEquals(3, root.getChildCount()); 161 Element b = (Element) root.getChild(1); 162 assertEquals("c", b.getQualifiedName()); 163 164 } 165 166 167 static class CFactory extends NodeFactory { 168 169 public Element startMakingElement( 170 String name, String namespace) { 171 return new Element("c"); 172 } 173 174 } 175 176 177 public void testMakeRoot() throws IOException , ParsingException { 178 179 String data = "<a><b>18</b></a>"; 180 Builder builder = new Builder(new CallsMakeRoot()); 181 Document doc = builder.build(data, "http://www.example.org/"); 182 Element root = doc.getRootElement(); 183 assertEquals("rootSubstitute", root.getQualifiedName()); 184 185 assertNotNull(root.getFirstChildElement("b")); 187 188 } 189 190 191 static class CallsMakeRoot extends NodeFactory { 192 193 public Element makeRootElement( 194 String name, String namepaceURI) { 195 return new Element("rootSubstitute"); 196 } 197 198 } 199 200 201 public void testSkippingProcessingInstruction() 202 throws IOException , ParsingException { 203 204 String data = "<a>1<?test some data?>8</a>"; 205 Builder builder = new Builder(new ProcessingInstructionFilter()); 206 Document doc = builder.build(data, "http://www.example.org/"); 207 Element root = doc.getRootElement(); 208 assertEquals( 209 "Skipped processing instruction interrupted text node", 210 2, root.getChildCount() 211 ); 212 assertEquals("18", doc.getValue()); 213 Node first = root.getChild(0); 214 assertEquals(first.getValue(), "1"); 215 Node second = root.getChild(1); 216 assertEquals(second.getValue(), "8"); 217 218 } 219 220 221 static class ProcessingInstructionFilter extends NodeFactory { 222 223 public Nodes makeProcessingInstruction( 224 String target, String data) { 225 return new Nodes(); 226 } 227 228 } 229 230 231 public void testSkipping2() throws IOException , ParsingException { 232 233 String data 234 = "<a>1<b>2<a>3<b>4<a>innermost</a>5</b>6</a>7</b>8</a>"; 235 Builder builder = new Builder(new BFilter()); 236 Document doc = builder.build(data, "http://www.example.org/"); 237 Element root = doc.getRootElement(); 238 assertEquals("1234innermost5678", doc.getValue()); 239 assertEquals(5, root.getChildCount()); 240 Node first = root.getChild(0); 241 assertEquals("1", first.getValue()); 242 Node middle = root.getChild(2); 243 assertEquals("34innermost56", middle.getValue()); 244 Node last = root.getChild(4); 245 assertEquals("8", last.getValue()); 246 247 Node innermost = middle.getChild(2); 248 assertEquals("innermost", innermost.getValue()); 249 Node inner1 = middle.getChild(0); 250 assertEquals("3", inner1.getValue()); 251 Node inner3 = middle.getChild(4); 252 assertEquals("6", inner3.getValue()); 253 254 } 255 256 257 static class BFilter extends NodeFactory { 258 259 public Element startMakingElement( 260 String name, String namespaceURI) { 261 if (name.equals("b")) return null; 262 return super.startMakingElement(name, namespaceURI); 263 } 264 265 } 266 267 268 public void testMinimalizedDocument() 269 throws IOException , ParsingException { 270 271 File input = new File (data, "entitytest.xml"); 272 Builder builder = new Builder(new MinimizingFactory()); 273 Document doc = builder.build(input); 274 assertEquals(1, doc.getChildCount()); 275 Element root = doc.getRootElement(); 276 assertEquals("root", root.getQualifiedName()); 277 assertEquals("", root.getNamespaceURI()); 278 assertEquals(0, root.getChildCount()); 279 assertEquals(0, root.getAttributeCount()); 280 281 } 282 283 284 public void testValidateWithFactory() 285 throws ParsingException, IOException { 286 Builder validator = new Builder(true, new MinimizingFactory()); 287 Document doc = validator.build("<!-- a comment --><!DOCTYPE root [" + 288 "<!ELEMENT root EMPTY>" + 289 "]>" + 290 "<root/><?a processing instruction?>", 291 "http://www.example.org/"); 292 assertEquals(1, doc.getChildCount()); 293 } 294 295 296 static class MinimizingFactory extends NodeFactory { 299 300 private Nodes empty = new Nodes(); 301 302 public Nodes makeComment(String data) { 303 return empty; 304 } 305 306 public Nodes makeText(String data) { 307 return empty; 308 } 309 310 public Nodes finishMakingElement(Element element) { 311 if (element.getParent() instanceof Document) { 312 return new Nodes(element); 313 } 314 return empty; 315 } 316 317 public Nodes makeAttribute(String name, String URI, 318 String value, Attribute.Type type) { 319 return empty; 320 } 321 322 public Nodes makeDocType(String rootElementName, 323 String publicID, String systemID) { 324 return empty; 325 } 326 327 public Nodes makeProcessingInstruction( 328 String target, String data) { 329 return empty; 330 } 331 332 } 333 334 335 public void testCDATASectionsCanBeOverridden() 336 throws ValidityException, ParsingException, IOException { 337 338 String data ="<root><![CDATA[text]]></root>"; 339 Builder builder = new Builder(new MinimizingFactory()); 340 Document doc = builder.build(data, "http://www.example.com"); 341 assertEquals("", doc.getValue()); 342 343 } 344 345 346 public void testNullRootNotAllowed() 347 throws IOException , ParsingException { 348 349 File input = new File (data, "entitytest.xml"); 350 Builder builder = new Builder(new NullElementFactory()); 351 try { 352 builder.build(input); 353 fail("Allowed null root"); 354 } 355 catch (ParsingException success) { 356 assertNotNull(success.getMessage()); 357 } 358 359 } 360 361 362 static class NullElementFactory extends NodeFactory { 365 366 public Element startMakingElement( 367 String name, String namespaceURI) { 368 return null; 369 } 370 371 } 372 373 374 public void testNullDocumentNotAllowed() 375 throws IOException , ParsingException { 376 377 File input = new File (data, "entitytest.xml"); 378 Builder builder = new Builder(new NullDocumentFactory()); 379 try { 380 builder.build(input); 381 fail("Allowed null document"); 382 } 383 catch (ParsingException success) { 384 assertTrue(success.getCause() instanceof NullPointerException ); 385 } 386 387 } 388 389 390 static class NullDocumentFactory extends NodeFactory { 393 394 public Document startMakingDocument() { 395 return null; 396 } 397 398 } 399 400 401 public void testSkipping() throws IOException , ParsingException { 402 403 String data = "<a>data<b>data<a>data</a>data</b>data</a>"; 404 Builder builder = new Builder(new BFilter()); 405 Document doc = builder.build(data, "http://www.example.org/"); 406 Element root = doc.getRootElement(); 407 assertEquals(5, root.getChildCount()); 408 assertEquals("datadatadatadatadata", root.getValue()); 409 Element middle = (Element) root.getChild(2); 410 assertEquals("data", middle.getValue()); 411 Node start = root.getChild(0); 412 Node end = root.getChild(4); 413 assertEquals("data", start.getValue()); 414 assertEquals("data", end.getValue()); 415 416 } 417 418 419 int numNodesInExternalDTDSubset = 0; 420 421 public void testDontReportCommentsAndProcessingInstructionsInExternalDTDSubset() 422 throws IOException , ParsingException { 423 424 File input = new File (data, "contentindtd.xml"); 425 Builder builder = new Builder(new Counter()); 426 builder.build(input); 427 assertEquals(0, numNodesInExternalDTDSubset); 428 429 } 430 431 432 private class Counter extends NodeFactory { 433 434 public Nodes makeComment(String data) { 435 numNodesInExternalDTDSubset++; 436 return super.makeComment(data); 437 } 438 439 public Nodes makeProcessingInstruction(String target, String data) { 440 numNodesInExternalDTDSubset++; 441 return super.makeProcessingInstruction(target, data); 442 } 443 444 } 445 446 447 public void testDontCoalesceTextNodes() 448 throws IOException , ParsingException { 449 450 String data = "<a>data<!-- comment--> data</a>"; 451 Builder builder = new Builder(new CommentFilter()); 452 Document doc = builder.build(data, "http://www.example.org/"); 453 Element root = doc.getRootElement(); 454 assertEquals(2, root.getChildCount()); 455 assertEquals("data data", root.getValue()); 456 Text text = (Text) root.getChild(0); 457 assertEquals("data", text.getValue()); 458 459 } 460 461 462 static class TripleElementFilter extends NodeFactory { 463 464 public Nodes finishMakingElement(Element element) { 465 Nodes result = new Nodes(element); 466 if (!(element.getParent() instanceof Document)) { 467 result.append(element.copy()); 468 result.append(element.copy()); 469 } 470 return result; 471 } 472 473 } 474 475 476 public void testTriple() 477 throws IOException , ParsingException { 478 479 String data = "<a><b><c/></b></a>"; 480 Builder builder = new Builder(new TripleElementFilter()); 481 Document doc = builder.build(data, "http://www.example.org/"); 482 Element root = doc.getRootElement(); 483 assertEquals(3, root.getChildCount()); 484 assertEquals("", root.getValue()); 485 Element b = (Element) root.getChild(0); 486 assertEquals("b", b.getLocalName()); 487 assertEquals( 488 "<a><b><c /><c /><c /></b><b><c /><c /><c /></b><b><c /><c /><c /></b></a>", 489 root.toXML()); 490 491 } 492 493 494 static class UncommentFilter extends NodeFactory { 495 496 public Nodes makeComment(String data) { 497 Nodes result = new Nodes(new Text(data)); 498 return result; 499 } 500 501 } 502 503 504 public void testUncomment() 505 throws ParsingException, IOException { 506 507 String data = "<!-- test --><a></a>"; 508 Builder builder = new Builder(new UncommentFilter()); 509 try { 510 builder.build(data, "http://www.example.org/"); 511 fail("built Text into prolog"); 512 } 513 catch (ParsingException success) { 514 assertNotNull(success.getMessage()); 515 } 516 517 } 518 519 520 static class DocumentFilter extends NodeFactory { 521 522 public Nodes makeComment(String data) { 523 Element root = new Element("root"); 524 Nodes result = new Nodes(new Document(root)); 525 return result; 526 } 527 528 } 529 530 531 public void testCantAddDocument() 532 throws ParsingException, IOException { 533 534 String data = "<a><!-- test --></a>"; 535 Builder builder = new Builder(new DocumentFilter()); 536 try { 537 builder.build(data, "http://www.example.org/"); 538 fail("built document into document"); 539 } 540 catch (ParsingException success) { 541 assertNotNull(success.getMessage()); 542 } 543 544 } 545 546 547 public void testCantAddTwoDoctypes() 548 throws ParsingException, IOException { 549 550 String data = "<!DOCTYPE a><a></a>"; 551 Builder builder = new Builder(new NodeFactory() { 552 553 public Nodes makeDocType(String name, String publicID, String systemID) { 554 Nodes result = new Nodes(); 555 result.append(new DocType(name, publicID, systemID)); 556 result.append(new Comment("sajdha")); 557 result.append(new DocType(name, publicID, systemID)); 558 return result; 559 } 560 561 }); 562 try { 563 builder.build(data, "http://www.example.org/"); 564 fail("built two doctypes"); 565 } 566 catch (ParsingException success) { 567 assertNotNull(success.getMessage()); 568 } 569 570 } 571 572 573 public void testChangeAttributesToElements() 574 throws ParsingException, IOException { 575 576 String data = "<a name=\"test\" value=\"data\"/>"; 577 Builder builder = new Builder(new NodeFactory() { 578 579 public Nodes makeAttribute(String name, String URI, 580 String value, Attribute.Type type) { 581 Nodes result = new Nodes(); 582 Element element = new Element(name, URI); 583 element.appendChild(value); 584 result.append(element); 585 return result; 586 } 587 588 }); 589 Document doc = builder.build(data, "http://www.example.org/"); 590 Element root = doc.getRootElement(); 591 assertEquals(2, root.getChildCount()); 592 Element name = root.getFirstChildElement("name"); 593 Element value = root.getFirstChildElement("value"); 594 assertEquals("test", name.getValue()); 595 assertEquals("data", value.getValue()); 596 assertEquals("name", name.getLocalName()); 597 assertEquals("value", value.getQualifiedName()); 598 599 } 600 601 602 public void testInsertElementsInInternalDTDSubsetViaProcessingInstruction() 603 throws ParsingException, IOException { 604 605 String data = "<!DOCTYPE a [<?target data?>]><a><b>data1</b><c>text</c></a>"; 606 Builder builder = new Builder(new NodeFactory() { 607 608 public Nodes makeProcessingInstruction(String target, String data) { 609 Nodes result = new Nodes(); 610 Element e = new Element(target); 611 e.appendChild(data); 612 result.append(e); 613 return result; 614 } 615 616 }); 617 try { 618 builder.build(data, "http://www.example.org/"); 619 fail("Allowed element in internal DTD subset via processing instruction"); 620 } 621 catch (ParsingException success) { 622 assertNotNull(success.getMessage()); 623 } 624 625 } 626 627 628 public void testInsertElementsInInternalDTDSubsetViaComment() 629 throws ParsingException, IOException { 630 631 String data = "<!DOCTYPE a [<!--data-->]><a><b>data1</b><c>text</c></a>"; 632 Builder builder = new Builder(new NodeFactory() { 633 634 public Nodes makeComment(String data) { 635 Nodes result = new Nodes(); 636 Element e = new Element("comment"); 637 e.appendChild(data); 638 result.append(e); 639 return result; 640 } 641 642 }); 643 try { 644 builder.build(data, "http://www.example.org/"); 645 fail("Allowed element in internal DTD subset via comment"); 646 } 647 catch (ParsingException success) { 648 assertNotNull(success.getMessage()); 649 } 650 651 } 652 653 654 public void testChangeElementsToAttributes() 655 throws ParsingException, IOException { 656 657 String data = "<a><b>data1</b><c>text</c></a>"; 658 Builder builder = new Builder(new NodeFactory() { 659 660 public Nodes finishMakingElement(Element element) { 661 Nodes result = new Nodes(); 662 if (element.getParent() instanceof Document) { 663 result.append(element); 664 } 665 else { 666 result.append(new Attribute(element.getLocalName(), element.getValue())); 667 } 668 return result; 669 } 670 671 }); 672 Document doc = builder.build(data, "http://www.example.org/"); 673 Element root = doc.getRootElement(); 674 assertEquals(0, root.getChildCount()); 675 assertEquals(2, root.getAttributeCount()); 676 assertEquals("data1", root.getAttribute("b").getValue()); 677 assertEquals("text", root.getAttribute("c").getValue()); 678 679 } 680 681 682 public void testChangeTextToAttributes() 683 throws ParsingException, IOException { 684 685 String data = "<a><b>data1</b><c>text</c></a>"; 686 Builder builder = new Builder(new NodeFactory() { 687 688 public Nodes makeText(String text) { 689 Nodes result = new Nodes(); 690 result.append(new Attribute("name", text)); 691 return result; 692 } 693 694 }); 695 Document doc = builder.build(data, "http://www.example.org/"); 696 Element root = doc.getRootElement(); 697 assertEquals(2, root.getChildCount()); 698 assertEquals(0, root.getAttributeCount()); 699 assertEquals("", root.getValue()); 700 Element b = root.getFirstChildElement("b"); 701 Element c = root.getFirstChildElement("c"); 702 assertEquals("data1", b.getAttribute("name").getValue()); 703 assertEquals("text", c.getAttribute("name").getValue()); 704 705 } 706 707 708 public void testChangeRootElementsToAttribute() 709 throws ParsingException, IOException { 710 711 String data = "<a><b>data1</b><c>text</c></a>"; 712 Builder builder = new Builder(new NodeFactory() { 713 714 public Nodes finishMakingElement(Element element) { 715 Nodes result = new Nodes(); 716 result.append(new Attribute(element.getLocalName(), element.getValue())); 717 return result; 718 } 719 720 }); 721 try { 722 builder.build(data, "http://www.example.org/"); 723 fail("replaced root element with attribute"); 724 } 725 catch (ParsingException success) { 726 assertNotNull(success.getMessage()); 727 } 728 729 } 730 731 732 public void testCantBypassMultipleParentChecks() 733 throws ParsingException, IOException { 734 735 String doc = "<root><a/><a/></root>"; 736 Builder builder = new Builder(new NodeFactory() { 737 738 private Element a = new Element("a"); 739 740 public Element startMakingElement(String name, String namespace) { 741 if (name.equals("a")) return a; 742 return new Element(name, namespace); 743 } 744 745 }); 746 try { 747 builder.build(doc, "http://www.example.org/"); 748 fail("built with multiple parents"); 749 } 750 &
|