| 1 21 22 package nu.xom.tests; 23 24 import java.io.ByteArrayOutputStream ; 25 import java.io.CharConversionException ; 26 import java.io.File ; 27 import java.io.FileNotFoundException ; 28 import java.io.FileOutputStream ; 29 import java.io.IOException ; 30 import java.io.OutputStreamWriter ; 31 import java.io.PrintStream ; 32 import java.io.Reader ; 33 import java.io.StringReader ; 34 import java.io.ByteArrayInputStream ; 35 import java.io.InputStream ; 36 import java.io.UTFDataFormatException ; 37 import java.io.Writer ; 38 import java.lang.reflect.Constructor ; 39 import java.lang.reflect.InvocationTargetException ; 40 41 import org.xml.sax.Attributes ; 42 import org.xml.sax.ContentHandler ; 43 import org.xml.sax.DTDHandler ; 44 import org.xml.sax.EntityResolver ; 45 import org.xml.sax.ErrorHandler ; 46 import org.xml.sax.InputSource ; 47 import org.xml.sax.Locator ; 48 import org.xml.sax.SAXException ; 49 import org.xml.sax.SAXNotRecognizedException ; 50 import org.xml.sax.SAXNotSupportedException ; 51 import org.xml.sax.SAXParseException ; 52 import org.xml.sax.XMLFilter ; 53 import org.xml.sax.XMLReader ; 54 import org.xml.sax.helpers.AttributesImpl ; 55 import org.xml.sax.helpers.LocatorImpl ; 56 import org.xml.sax.helpers.XMLFilterImpl ; 57 import org.xml.sax.helpers.XMLReaderFactory ; 58 59 import nu.xom.Attribute; 60 import nu.xom.Builder; 61 import nu.xom.Comment; 62 import nu.xom.DocType; 63 import nu.xom.Document; 64 import nu.xom.Element; 65 import nu.xom.IllegalNameException; 66 import nu.xom.NodeFactory; 67 import nu.xom.ParsingException; 68 import nu.xom.ProcessingInstruction; 69 import nu.xom.ValidityException; 70 import nu.xom.XMLException; 71 72 73 83 public class BuilderTest extends XOMTestCase { 84 85 86 private File inputDir = new File ("data"); 87 88 private static class CustomReader implements XMLReader { 91 92 private ContentHandler handler; 93 94 public void parse(String data) throws SAXException { 95 handler.startDocument(); 96 handler.startElement("87", "87", "87", new AttributesImpl ()); 97 handler.endElement("87", "87", "87"); 98 handler.endDocument(); 99 } 100 101 public boolean getFeature(String uri) { 102 return false; 103 } 104 105 public void setFeature(String uri, boolean value) {} 106 107 public ContentHandler getContentHandler() { 108 return handler; 109 } 110 111 public void setContentHandler(ContentHandler handler) { 112 this.handler = handler; 113 } 114 115 public DTDHandler getDTDHandler() { 116 return null; 117 } 118 119 public void setDTDHandler(DTDHandler handler) { 120 } 121 122 public EntityResolver getEntityResolver() { 123 return null; 124 } 125 126 public void setEntityResolver(EntityResolver resolver) {} 127 128 public ErrorHandler getErrorHandler() { 129 return null; 130 } 131 132 public void setErrorHandler(ErrorHandler handler) {} 133 134 public void parse(InputSource arg0) throws IOException , 135 SAXException {} 136 137 public Object getProperty(String uri) { 138 return null; 139 } 140 141 public void setProperty(String uri, Object value) {} 142 143 } 144 145 146 public BuilderTest(String name) { 147 super(name); 148 } 149 150 151 private PrintStream systemErr = System.err; 155 156 protected void setUp() { 157 System.setErr(new PrintStream (new ByteArrayOutputStream ())); 158 } 159 160 161 protected void tearDown() { 162 System.setErr(systemErr); 163 } 164 165 166 167 168 private boolean xercesBroken = false; 171 172 private String elementDeclaration = "<!ELEMENT root (#PCDATA)>"; 173 private String defaultAttributeDeclaration 174 = "<!ATTLIST test name CDATA \"value\">"; 175 private String attributeDeclaration 176 = "<!ATTLIST root anattribute CDATA #REQUIRED>"; 177 private String attributeDeclaration2 178 = "<!ATTLIST root anotherattribute CDATA \"value\">"; 179 private String unparsedEntityDeclaration 180 = "<!ENTITY hatch-pic SYSTEM " + 181 "\"http://www.example.com/images/cup.gif\" NDATA gif>"; 182 private String unparsedEntityDeclarationPublic 183 = "<!ENTITY public-pic PUBLIC \"public ID\" " + 184 "\"http://www.example.com/images/cup.gif\" NDATA gif>"; 185 private String internalEntityDeclaration 186 = "<!ENTITY Pub-Status \"" + 187 "This is a pre-release of the specification.\">"; 188 private String externalEntityDeclarationPublic = 189 "<!ENTITY open-hatch " 190 + "PUBLIC \"-//Textuality//TEXT Standard " + 191 "open-hatch boilerplate//EN\" " 192 + "\"http://www.textuality.com/boilerplate/OpenHatch.xml\">"; 193 private String externalEntityDeclarationSystem = 194 "<!ENTITY test SYSTEM " + 195 "\"http://www.textuality.com/boilerplate/OpenHatch.xml\">"; 196 private String notationDeclarationSystem 197 = "<!NOTATION ISODATE SYSTEM " 198 + "\"http://www.iso.ch/cate/d15903.html\">"; 199 private String notationDeclarationPublicAndSystem 200 = "<!NOTATION DATE PUBLIC \"DATE PUBLIC ID\" " 201 + "\"http://www.iso.ch/cate/d15903.html\">"; 202 private String notationDeclarationPublic = "<!NOTATION gif PUBLIC " 203 + "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\">"; 204 205 private String source = "<!DOCTYPE test [\r\n" 206 + elementDeclaration + "\n" 207 + attributeDeclaration + "\n" 208 + defaultAttributeDeclaration + "\n" 209 + attributeDeclaration2 + "\n" 210 + internalEntityDeclaration + "\n" 211 + externalEntityDeclarationPublic + "\n" 212 + externalEntityDeclarationSystem + "\n" 213 + unparsedEntityDeclaration + "\n" 214 + unparsedEntityDeclarationPublic + "\n" 215 + notationDeclarationPublic + "\n" 216 + notationDeclarationSystem + "\n" 217 + notationDeclarationPublicAndSystem + "\n" 218 + "]>\r\n" 219 + "<?xml-stylesheet HREF=\"file.css\" type=\"text/css\"?>" 220 + "<!-- test -->" 221 + "<test xmlns:xlink='http://www.w3.org/TR/1999/xlink'>Hello dear" 222 + "\r\n<em id=\"p1\" xmlns:none=\"http://www.example.com\">" 223 + "very important</em>" 224 + "<span xlink:type='simple'>here's the link</span>\r\n" 225 + "<svg:svg xmlns:svg='http://www.w3.org/TR/2000/svg'>" 226 + "<svg:text>text in a namespace</svg:text></svg:svg>\r\n" 227 + "<svg xmlns='http://www.w3.org/TR/2000/svg'><text>text in a " 228 + "namespace</text></svg></test>\r\n<!--epilog-->"; 229 230 private String validDoc = "<!DOCTYPE test [\r\n" 231 + "<!ELEMENT test (#PCDATA)>\n" 232 + "]>\r\n" 233 + "<?xml-stylesheet HREF=\"file.css\" type=\"text/css\"?>" 234 + "<!-- test -->" 235 + "<test>Hello dear</test>" 236 + "<!--epilog-->"; 237 238 private Builder builder = new Builder(); 239 private Builder validator = new Builder(true); 240 private String base = "http://www.example.com/"; 241 242 private String attributeDoc = "<!DOCTYPE test [\n" 243 + "<!ELEMENT test (#PCDATA)>\n" 244 + "<!NOTATION GIF SYSTEM \"text/gif\">\n" 245 + "<!ENTITY data SYSTEM \"http://www.example.org/cup.gif\">\n" 246 + "<!ATTLIST test notationatt NOTATION (GIF) \"GIF\">\n" 247 + "<!ATTLIST test cdataatt CDATA \"GIF\">\n" 248 + "<!ATTLIST test entityatt ENTITY \"data\">\n" 249 + "<!ATTLIST test entitiesatt ENTITIES \"data\">\n" 250 + "<!ATTLIST test nmtokenatt NMTOKEN \" 1 \">\n" 251 + "<!ATTLIST test nmtokensatt NMTOKENS \" 1 2 3 \">\n" 252 + "<!ATTLIST test idatt ID \" p1 \">\n" 253 + "<!ATTLIST test idrefatt IDREF \" p1 \">\n" 254 + "<!ATTLIST test idrefsatt IDREFS \" p1 p2 \">\n" 255 + "]>\r\n" 256 + "<test>Hello dear</test>"; 257 258 259 public void testNotationAttributeType() 260 throws IOException , ParsingException { 261 262 Reader reader = new StringReader (attributeDoc); 263 Document document = builder.build(reader); 264 Element root = document.getRootElement(); 265 Attribute att = root.getAttribute("notationatt"); 266 assertEquals(Attribute.Type.NOTATION, att.getType()); 267 268 } 269 270 271 public void testBuildInternalDTDSubsetWithFixedDefaultAttributeValue() 272 throws ParsingException, IOException { 273 274 String doctype = "<!DOCTYPE xsl:stylesheet [\n" 275 + "<!ATTLIST a b CDATA #FIXED \"c\">]>"; 276 String document = doctype + "\n<root/>"; 277 Builder builder = new Builder(); 278 Document doc = builder.build(document, null); 279 DocType dt = doc.getDocType(); 280 String internalDTDSubset = dt.getInternalDTDSubset(); 281 assertTrue(internalDTDSubset.indexOf("#FIXED \"c\"") > 0); 282 283 } 284 285 286 public void testCDATAAttributeType() 287 throws IOException , ParsingException { 288 289 Reader reader = new StringReader (attributeDoc); 290 Document document = builder.build(reader); 291 Element root = document.getRootElement(); 292 Attribute att = root.getAttribute("cdataatt"); 293 assertEquals(Attribute.Type.CDATA, att.getType()); 294 295 } 296 297 298 public void testEntityAttributeType() 299 throws IOException , ParsingException { 300 301 Reader reader = new StringReader (attributeDoc); 302 Document document = builder.build(reader); 303 Element root = document.getRootElement(); 304 Attribute att = root.getAttribute("entityatt"); 305 assertEquals(Attribute.Type.ENTITY, att.getType()); 306 307 } 308 309 310 public void testEntitiesAttributeType() 311 throws IOException , ParsingException { 312 313 Reader reader = new StringReader (attributeDoc); 314 Document document = builder.build(reader); 315 Element root = document.getRootElement(); 316 Attribute att = root.getAttribute("entitiesatt"); 317 assertEquals(Attribute.Type.ENTITIES, att.getType()); 318 319 } 320 321 322 public void testNameTokenAttributeType() 323 throws IOException , ParsingException { 324 325 Reader reader = new StringReader (attributeDoc); 326 Document document = builder.build(reader); 327 Element root = document.getRootElement(); 328 Attribute att = root.getAttribute("nmtokenatt"); 329 assertEquals(Attribute.Type.NMTOKEN, att.getType()); 330 assertEquals("1", att.getValue()); 331 332 } 333 334 335 public void testIllegalSystemIDThrowsRightException() { 337 338 String document = "<!DOCTYPE root SYSTEM \"This is not a URI\"><root/>"; 339 try{ 340 builder.build(document, null); 341 } 342 catch (Exception ex) { 343 assertTrue(ex instanceof ParsingException); 344 } 345 346 } 347 348 349 public void testNameTokensAttributeType() 350 throws IOException , ParsingException { 351 352 Reader reader = new StringReader (attributeDoc); 353 Document document = builder.build(reader); 354 Element root = document.getRootElement(); 355 Attribute att = root.getAttribute("nmtokensatt"); 356 assertEquals(Attribute.Type.NMTOKENS, att.getType()); 357 assertEquals("1 2 3", att.getValue()); 358 359 } 360 361 362 public void testXML11() throws IOException { 364 365 String data = "<?xml version='1.1'?><root/>"; 366 try { 367 builder.build(data, "http://www.example.com"); 368 fail("XML 1.1 allowed"); 369 } 370 catch (ParsingException ex) { 371 assertNotNull(ex.getMessage()); 372 } 373 374 } 375 376 377 public void testXML12() throws IOException { 379 380 String data = "<?xml version='1.2'?><root/>"; 381 try { 382 builder.build(data, "http://www.example.com"); 383 fail("XML 1.2 allowed"); 384 } 385 catch (ParsingException ex) { 386 assertNotNull(ex.getMessage()); 387 } 388 389 } 390 391 392 public void testXML20() throws IOException { 394 395 String data = "<?xml version='2.0'?><root/>"; 396 try { 397 builder.build(data, "http://www.example.com"); 398 fail("XML 2.0 allowed"); 399 } 400 catch (ParsingException ex) { 401 assertNotNull(ex.getMessage()); 402 } 403 404 } 405 406 407 public void testIDAttributeType() 408 throws IOException , ParsingException { 409 410 Reader reader = new StringReader (attributeDoc); 411 Document document = builder.build(reader); 412 Element root = document.getRootElement(); 413 Attribute att = root.getAttribute("idatt"); 414 assertEquals(Attribute.Type.ID, att.getType()); 415 assertEquals("p1", att.getValue()); 416 417 } 418 419 420 public void testIDREFAttributeType() 421 throws IOException , ParsingException { 422 423 Reader reader = new StringReader (attributeDoc); 424 Document document = builder.build(reader); 425 Element root = document.getRootElement(); 426 Attribute att = root.getAttribute("idrefatt"); 427 assertEquals(Attribute.Type.IDREF, att.getType()); 428 assertEquals("p1", att.getValue()); 429 430 } 431 432 433 public void testIDREFSAttributeType() 434 throws IOException , ParsingException { 435 436 Reader reader = new StringReader (attributeDoc); 437 Document document = builder.build(reader); 438 Element root = document.getRootElement(); 439 Attribute att = root.getAttribute("idrefsatt"); 440 assertEquals(Attribute.Type.IDREFS, att.getType()); 441 assertEquals("p1 p2", att.getValue()); 442 443 } 444 445 446 public void testBuildFromReader() 447 throws IOException , ParsingException { 448 449 Reader reader = new StringReader (source); 450 Document document = builder.build(reader); 451 verify(document); 452 assertEquals("", document.getBaseURI()); 453 454 } 455 456 457 public void testBuildFromReaderWithBase() 458 throws IOException , ParsingException { 459 460 Reader reader = new StringReader (source); 461 Document document = builder.build(reader, base); 462 verify(document); 463 assertEquals(base, document.getBaseURI()); 464 465 } 466 467 468 private static class NoLocator extends XMLFilterImpl { 469 470 public NoLocator(XMLReader reader) { 471 super(reader); 472 } 473 474 public void setDocumentLocator(Locator locator) {} 475 476 } 477 478 479 public void testBuildWithoutLocator() 480 throws IOException , ParsingException, SAXException { 481 482 XMLReader xerces = XMLReaderFactory.createXMLReader( 483 "org.apache.xerces.parsers.SAXParser"); 484 XMLReader filter = new NoLocator(xerces); 485 486 Builder builder = new Builder(filter); 487 Document document = builder.build(source, "http://www.example.org/"); 488 verify(document); 489 assertEquals("http://www.example.org/", document.getBaseURI()); 490 491 } 492 493 494 private static class WeirdAttributeTypes extends XMLFilterImpl { 495 496 public WeirdAttributeTypes(XMLReader reader) { 497 super(reader); 498 } 499 500 public void startElement(String uri, String localName, 501 String qualifiedName, Attributes atts) throws SAXException { 502 503 AttributesImpl newAtts = new AttributesImpl (atts); 504 for (int i = 0; i < newAtts.getLength(); i++) { 505 newAtts.setType(i, "WEIRD"); 506 } 507 508 super.startElement(uri, localName, qualifiedName, newAtts); 509 510 } 511 512 } 513 514 515 public void testWeirdAttributeTypes() 516 throws IOException , ParsingException, SAXException { 517 518 XMLReader xerces = XMLReaderFactory.createXMLReader( 519 "org.apache.xerces.parsers.SAXParser"); 520 XMLReader filter = new WeirdAttributeTypes(xerces); 521 522 Builder builder = new Builder(filter); 523 Document document = builder.build(attributeDoc, "http://www.example.org/"); 524 Element root = document.getRootElement(); 525 assertTrue(root.getAttributeCount() > 0); 526 for (int i = 0; i < root.getAttributeCount(); i++) { 527 assertEquals(Attribute.Type.UNDECLARED, root.getAttribute(i).getType()); 528 } 529 530 } 531 532 533 private static class ParenthesizedEnumeratedAttributeTypes extends XMLFilterImpl { 535 536 public ParenthesizedEnumeratedAttributeTypes(XMLReader reader) { 537 super(reader); 538 } 539 540 public void startElement(String uri, String localName, 541 String qualifiedName, Attributes atts) throws SAXException { 542 543 AttributesImpl newAtts = new AttributesImpl (atts); 544 for (int i = 0; i < newAtts.getLength(); i++) { 545 newAtts.setType(i, "(test, data, value)"); 546 } 547 548 super.startElement(uri, localName, qualifiedName, newAtts); 549 550 } 551 552 } 553 554 555 public void testParenthesizedEnumeratedAttributeTypes() 556 throws IOException , ParsingException, SAXException { 557 558 XMLReader xerces = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); 559 XMLReader filter = new ParenthesizedEnumeratedAttributeTypes(xerces); 560 561 Builder builder = new Builder(filter); 562 Document document = builder.build(attributeDoc, "http://www.example.org/"); 563 Element root = document.getRootElement(); 564 assertTrue(root.getAttributeCount() > 0); 565 for (int i = 0; i < root.getAttributeCount(); i++) { 566 assertEquals(Attribute.Type.ENUMERATION, root.getAttribute(i).getType()); 567 } 568 569 } 570 571 572 public void testBuildFromInputStreamWithBase() 573 throws IOException , ParsingException { 574 InputStream in = new ByteArrayInputStream (source.getBytes("UTF-8")); 575 Document document = builder.build(in, base); 576 verify(document); 577 assertEquals(base, document.getBaseURI()); 578 } 579 580 581 public void testBuildFromInputStreamWithoutBase() 582 throws IOException , ParsingException { 583 InputStream in = new ByteArrayInputStream (source.getBytes("UTF-8")); 584 Document document = builder.build(in); 585 verify(document); 586 assertEquals("", document.getBaseURI()); 587 } 588 589 590 public void testBuildFromStringWithBase() 591 throws IOException , ParsingException { 592 Document document = builder.build(source, base); 593 verify(document); 594 assertEquals(base, document.getBaseURI()); 595 } 596 597 598 public void testBuildFromInvalidDoc() 599 throws IOException , ParsingException { 600 601 try { 602 validator.build(source, base); 603 fail("Built invalid doc"); 604 } 605 catch (ValidityException ex) { 606 Document document = ex.getDocument(); 607 assertTrue(document.getChild(1) instanceof ProcessingInstruction); 610 assertTrue(document.getChild(2) instanceof Comment); 611 DocType doctype = document.getDocType(); 612 Element root = document.getRootElement(); 613 614 assertEquals("test", root.getQualifiedName()); 617 assertEquals("test", root.getLocalName()); 618 assertEquals("", root.getNamespaceURI()); 619 620 assertTrue(doctype != null); 621 assertTrue(document.getChild(0) instanceof DocType); 622 assertTrue(document.getChild(4) instanceof Comment); 623 assertTrue(document.getChild(2) instanceof Comment); 624 assertEquals(" test ", document.getChild(2).getValue()); 625 assertEquals("epilog", document.getChild(4).getValue()); 626 assertTrue(document.getChild(1) instanceof ProcessingInstruction); 627 assertEquals("test", doctype.getRootElementName()); 628 assertNull(doctype.getPublicID()); 629 assertNull(doctype.getSystemID()); 630 631 String internalDTDSubset = doctype.getInternalDTDSubset(); 632 assertTrue( 633 internalDTDSubset, 634 internalDTDSubset.indexOf(elementDeclaration) > 0 635 ); 636 assertTrue( 637 internalDTDSubset, 638 internalDTDSubset.indexOf(attributeDeclaration) > 0 639 ); 640 assertTrue( 641 internalDTDSubset, 642 internalDTDSubset.indexOf(attributeDeclaration2) > 0 643 ); 644 assertTrue( 645 internalDTDSubset, 646 internalDTDSubset.indexOf(internalEntityDeclaration) > 0 647 ); 648 assertTrue( 649 internalDTDSubset, 650 internalDTDSubset.indexOf(externalEntityDeclarationPublic) > 0 651 ); 652 assertTrue( 653 internalDTDSubset, 654 internalDTDSubset.indexOf(externalEntityDeclarationSystem) > 0 655 ); 656 assertTrue( 657 internalDTDSubset, 658 internalDTDSubset.indexOf(unparsedEntityDeclaration) > 0 659 ); 660 assertTrue( 661 internalDTDSubset, 662 internalDTDSubset.indexOf(unparsedEntityDeclarationPublic) > 0 663 ); 664 assertTrue( 665 internalDTDSubset, 666 internalDTDSubset.indexOf(notationDeclarationPublic) > 0 667 ); 668 assertTrue( 669 internalDTDSubset, 670 internalDTDSubset.indexOf(notationDeclarationSystem) > 0 671 ); 672 assertTrue( 673 internalDTDSubset, 674 internalDTDSubset.indexOf(notationDeclarationPublicAndSystem) > 0 675 ); 676 677 } 678 679 } 680 681 682 public void testBuildFromStringWithNullBase() 683 throws IOException , ParsingException { 684 Document document = builder.build(source, null); 685 verify(document); 686 assertEquals("", document.getBaseURI()); 687 } 688 689 690 private void verify(Document document) { 691 692 assertTrue(document.getChild(1) instanceof ProcessingInstruction); 693 assertTrue(document.getChild(2) instanceof Comment); 694 DocType doctype = document.getDocType(); 695 Element root = document.getRootElement(); 696 697 assertEquals(1, root.getAttributeCount()); 698 assertEquals("value", root.getAttributeValue("name")); 699 assertEquals("test", root.getQualifiedName()); 700 assertEquals("test", root.getLocalName()); 701 assertEquals("", root.getNamespaceURI()); 702 703 assertTrue(doctype != null); 704 assertTrue(document.getChild(0) instanceof DocType); 705 assertTrue(document.getChild(4) instanceof Comment); 706 assertTrue(document.getChild(2) instanceof Comment); 707 assertEquals(" test ", document.getChild(2).getValue()); 708 assertEquals("epilog", document.getChild(4).getValue()); 709 assertTrue(document.getChild(1) instanceof ProcessingInstruction); 710 assertEquals("test", doctype.getRootElementName()); 711 assertNull(doctype.getPublicID()); 712 assertNull(doctype.getSystemID()); 713 714 String internalDTDSubset = doctype.getInternalDTDSubset(); 715 assertTrue( 716 internalDTDSubset, 717 internalDTDSubset.indexOf(elementDeclaration) > 0 718 ); 719 assertTrue( 720 internalDTDSubset, 721 internalDTDSubset.indexOf(attributeDeclaration) > 0 722 ); 723 assertTrue( 724 internalDTDSubset, 725 internalDTDSubset.indexOf(attributeDeclaration2) > 0 726 ); 727 assertTrue( 728 internalDTDSubset, 729 internalDTDSubset.indexOf(internalEntityDeclaration) > 0 730 ); 731 assertTrue( 732 internalDTDSubset, 733 internalDTDSubset.indexOf(externalEntityDeclarationPublic) > 0 734 ); 735 assertTrue( 736 internalDTDSubset, 737 internalDTDSubset.indexOf(externalEntityDeclarationSystem) > 0 738 ); 739 assertTrue( 740 internalDTDSubset, 741 internalDTDSubset.indexOf(unparsedEntityDeclaration) > 0 742 ); 743 &nbs
|