001: /* Copyright 2002-2005 Elliotte Rusty Harold
002:
003: This library is free software; you can redistribute it and/or modify
004: it under the terms of version 2.1 of the GNU Lesser General Public
005: License as published by the Free Software Foundation.
006:
007: This library is distributed in the hope that it will be useful,
008: but WITHOUT ANY WARRANTY; without even the implied warranty of
009: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: GNU Lesser General Public License for more details.
011:
012: You should have received a copy of the GNU Lesser General Public
013: License along with this library; if not, write to the
014: Free Software Foundation, Inc., 59 Temple Place, Suite 330,
015: Boston, MA 02111-1307 USA
016:
017: You can contact Elliotte Rusty Harold by sending e-mail to
018: elharo@metalab.unc.edu. Please include the word "XOM" in the
019: subject line. The XOM home page is located at http://www.xom.nu/
020: */
021:
022: package nu.xom.tests;
023:
024: import java.io.ByteArrayInputStream;
025: import java.io.File;
026: import java.io.IOException;
027: import java.io.Reader;
028: import java.io.StringReader;
029:
030: import javax.xml.parsers.DocumentBuilder;
031: import javax.xml.parsers.DocumentBuilderFactory;
032: import javax.xml.parsers.ParserConfigurationException;
033:
034: import nu.xom.Attribute;
035: import nu.xom.Builder;
036: import nu.xom.Comment;
037: import nu.xom.DocType;
038: import nu.xom.Document;
039: import nu.xom.Element;
040: import nu.xom.Nodes;
041: import nu.xom.ParsingException;
042: import nu.xom.ProcessingInstruction;
043: import nu.xom.Text;
044: import nu.xom.XMLException;
045: import nu.xom.converters.DOMConverter;
046:
047: import org.w3c.dom.CDATASection;
048: import org.w3c.dom.DOMImplementation;
049: import org.w3c.dom.DocumentFragment;
050: import org.xml.sax.InputSource;
051: import org.xml.sax.SAXException;
052:
053: /**
054: * <p>
055: * Basic tests for conversion from DOM trees to XOM trees
056: * and back again.
057: * </p>
058: *
059: * @author Elliotte Rusty Harold
060: * @version 1.1b2
061: *
062: */
063: public class DOMConverterTest extends XOMTestCase {
064:
065: public DOMConverterTest(String name) {
066: super (name);
067: }
068:
069: private String source = "<!DOCTYPE test [ ]>\r\n"
070: + "<?xml-stylesheet href=\"file.css\" type=\"text/css\"?>"
071: + "<!-- test -->"
072: + "<test xmlns:xlink='http://www.w3.org/TR/1999/xlink'>Hello dear"
073: + "\r\n<em id=\"p1\" "
074: + "xmlns:none=\"http://www.example.com\">very important</em>"
075: + "<span xlink:type='simple'>here's the link</span>\r\n"
076: + "<svg:svg xmlns:svg='http://www.w3.org/TR/2000/svg'><svg:text>"
077: + "text in a namespace</svg:text></svg:svg>\r\n"
078: + "<svg xmlns='http://www.w3.org/TR/2000/svg'><text>text in a "
079: + "namespace</text></svg>" + "</test>\r\n"
080: + "<!--epilog-->";
081:
082: private Document xomDocument;
083: private org.w3c.dom.Document domDocument;
084: private DOMImplementation impl;
085: private DocumentBuilder builder;
086:
087: protected void setUp() throws ParserConfigurationException {
088:
089: DocumentBuilderFactory factory = DocumentBuilderFactory
090: .newInstance();
091: factory.setNamespaceAware(true);
092: builder = factory.newDocumentBuilder();
093: impl = builder.getDOMImplementation();
094:
095: DocType type = new DocType("test");
096: Element root = new Element("test");
097: xomDocument = new Document(root);
098: xomDocument.insertChild(type, 0);
099: xomDocument.insertChild(
100: new ProcessingInstruction("xml-stylesheet",
101: "href=\"file.css\" type=\"text/css\""), 1);
102: xomDocument.insertChild(new Comment(" test "), 2);
103: xomDocument.appendChild(new Comment("epilog"));
104: root.addNamespaceDeclaration("xlink",
105: "http://www.w3.org/TR/1999/xlink");
106: root.appendChild("Hello dear\r\n");
107: Element em = new Element("em");
108: root.appendChild(em);
109: em.addAttribute(new Attribute("id", "p1"));
110: em.addNamespaceDeclaration("none", "http://www.example.com");
111: em.appendChild("very important");
112: Element span = new Element("span");
113: root.appendChild(span);
114: span.addAttribute(new Attribute("xlink:type",
115: "http://www.w3.org/TR/1999/xlink", "simple"));
116: span.appendChild("here's the link");
117: root.appendChild("\r\n");
118:
119: Element empty = new Element("empty");
120: root.appendChild(empty);
121: empty
122: .addAttribute(new Attribute("xom:temp",
123: "http://xom.nu/",
124: "Just to see if this can handle namespaced attributes"));
125:
126: root.appendChild("\r\n");
127: Element svg = new Element("svg:svg",
128: "http://www.w3.org/TR/2000/svg");
129: root.appendChild(svg);
130: Element text = new Element("svg:text",
131: "http://www.w3.org/TR/2000/svg");
132: svg.appendChild(text);
133: text.appendChild("text in a namespace");
134: root.appendChild("\r\n");
135:
136: svg = new Element("svg", "http://www.w3.org/TR/2000/svg");
137: root.appendChild(svg);
138: text = new Element("text", "http://www.w3.org/TR/2000/svg");
139: svg.appendChild(text);
140: text.appendChild("text in a namespace");
141:
142: Reader reader = new StringReader(source);
143: InputSource inso = new InputSource(reader);
144:
145: try {
146: domDocument = builder.parse(inso);
147: } catch (Exception ex) {
148: // shouldn't happen from known good doc
149: throw new RuntimeException("Oops!");
150: }
151:
152: }
153:
154: public void testToDOM() {
155:
156: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocument,
157: impl);
158: org.w3c.dom.DocumentType doctype = domDoc.getDoctype();
159:
160: assertEquals("test", domDoc.getDocumentElement().getNodeName());
161: assertTrue(doctype != null);
162: assertEquals(org.w3c.dom.Node.DOCUMENT_TYPE_NODE, domDoc
163: .getFirstChild().getNodeType());
164: assertEquals(org.w3c.dom.Node.COMMENT_NODE, domDoc
165: .getLastChild().getNodeType());
166:
167: }
168:
169: public void testToXOM() {
170:
171: Document xomDoc = DOMConverter.convert(domDocument);
172: DocType doctype = xomDoc.getDocType();
173: Element root = xomDoc.getRootElement();
174:
175: assertEquals("test", root.getQualifiedName());
176: assertEquals("test", root.getLocalName());
177: assertEquals("", root.getNamespaceURI());
178:
179: assertTrue(doctype != null);
180: assertTrue(xomDoc.getChild(0) instanceof DocType);
181: assertTrue(xomDoc.getChild(4) instanceof nu.xom.Comment);
182: assertTrue(xomDoc.getChild(2) instanceof nu.xom.Comment);
183: assertEquals(" test ", xomDoc.getChild(2).getValue());
184: assertEquals("epilog", xomDoc.getChild(4).getValue());
185: assertTrue(xomDoc.getChild(1) instanceof nu.xom.ProcessingInstruction);
186: assertEquals("test", doctype.getRootElementName());
187: assertNull(doctype.getPublicID());
188: assertNull(doctype.getSystemID());
189:
190: }
191:
192: public void testDefaultNamespacedElement() throws SAXException,
193: IOException, ParserConfigurationException {
194:
195: byte[] data = "<root xmlns=\"http://www.example.com\"/>"
196: .getBytes();
197: org.w3c.dom.Document doc = builder
198: .parse(new ByteArrayInputStream(data));
199: Document xomDoc = DOMConverter.convert(doc);
200:
201: Element root = xomDoc.getRootElement();
202: assertEquals("root", root.getQualifiedName());
203: assertEquals("http://www.example.com", root.getNamespaceURI());
204:
205: }
206:
207: public void testPrefixedElement() throws SAXException, IOException,
208: ParserConfigurationException {
209:
210: byte[] data = "<pre:root xmlns:pre=\"http://www.example.com\"/>"
211: .getBytes();
212: org.w3c.dom.Document doc = builder
213: .parse(new ByteArrayInputStream(data));
214: Document xomDoc = DOMConverter.convert(doc);
215:
216: Element root = xomDoc.getRootElement();
217: assertEquals("pre:root", root.getQualifiedName());
218: assertEquals("http://www.example.com", root.getNamespaceURI());
219:
220: }
221:
222: public void testConvertAttr() throws SAXException, IOException,
223: ParserConfigurationException {
224:
225: byte[] data = ("<element name='value' "
226: + "xmlns='http://example.com/' "
227: + "xmlns:pre='http://example.net'/>").getBytes();
228: org.w3c.dom.Document doc = builder
229: .parse(new ByteArrayInputStream(data));
230:
231: org.w3c.dom.Element root = doc.getDocumentElement();
232: Attribute attribute = DOMConverter.convert(root
233: .getAttributeNode("name"));
234: assertEquals("name", attribute.getQualifiedName());
235: assertEquals("", attribute.getNamespacePrefix());
236: assertEquals("", attribute.getNamespaceURI());
237: assertEquals("value", attribute.getValue());
238:
239: try {
240: DOMConverter.convert(root.getAttributeNode("xmlns"));
241: fail("Converted xmlns attribute");
242: } catch (XMLException ex) {
243: assertNotNull(ex.getMessage());
244: }
245: try {
246: DOMConverter.convert(root.getAttributeNode("xmlns:pre"));
247: fail("Converted xmlns:pre attribute");
248: } catch (XMLException ex) {
249: assertNotNull(ex.getMessage());
250: }
251:
252: }
253:
254: public void testConvertElement() throws SAXException, IOException,
255: ParserConfigurationException {
256:
257: byte[] data = ("<element name='value' "
258: + "xmlns='http://example.com/' "
259: + "xmlns:pre='http://example.net'/>").getBytes();
260: org.w3c.dom.Document doc = builder
261: .parse(new ByteArrayInputStream(data));
262:
263: org.w3c.dom.Element root = doc.getDocumentElement();
264: Element xomRoot = DOMConverter.convert(root);
265: assertEquals("name", xomRoot.getAttribute("name")
266: .getQualifiedName());
267: assertEquals("", xomRoot.getAttribute("name")
268: .getNamespacePrefix());
269: assertEquals("", xomRoot.getAttribute("name").getNamespaceURI());
270: assertEquals("value", xomRoot.getAttribute("name").getValue());
271: assertEquals("element", xomRoot.getQualifiedName());
272: assertEquals("", xomRoot.getValue());
273: assertEquals(0, xomRoot.getChildCount());
274: assertEquals("http://example.com/", xomRoot.getNamespaceURI());
275: assertEquals("http://example.net", xomRoot
276: .getNamespaceURI("pre"));
277:
278: }
279:
280: public void testConvertComment() throws SAXException, IOException,
281: ParserConfigurationException {
282:
283: byte[] data = "<element><!--data--></element>".getBytes();
284: org.w3c.dom.Document doc = builder
285: .parse(new ByteArrayInputStream(data));
286:
287: org.w3c.dom.Element root = doc.getDocumentElement();
288: org.w3c.dom.Comment comment = (org.w3c.dom.Comment) (root
289: .getChildNodes().item(0));
290: Comment xomComment = DOMConverter.convert(comment);
291: assertEquals(comment.getNodeValue(), xomComment.getValue());
292:
293: }
294:
295: public void testConvertText() throws SAXException, IOException,
296: ParserConfigurationException {
297:
298: byte[] data = "<element> here's the text </element>".getBytes();
299: org.w3c.dom.Document doc = builder
300: .parse(new ByteArrayInputStream(data));
301:
302: org.w3c.dom.Element root = doc.getDocumentElement();
303: org.w3c.dom.Text node = (org.w3c.dom.Text) (root
304: .getChildNodes().item(0));
305: Text text = DOMConverter.convert(node);
306: assertEquals(node.getNodeValue(), text.getValue());
307:
308: }
309:
310: public void testConvertCDATASection() throws SAXException,
311: IOException, ParserConfigurationException {
312:
313: byte[] data = "<element><![CDATA[ here's the text ]]></element>"
314: .getBytes();
315: org.w3c.dom.Document doc = builder
316: .parse(new ByteArrayInputStream(data));
317:
318: org.w3c.dom.Element root = doc.getDocumentElement();
319: CDATASection node = (CDATASection) (root.getChildNodes()
320: .item(0));
321: Text text = DOMConverter.convert(node);
322: assertEquals(node.getNodeValue(), text.getValue());
323:
324: // Now test indirect conversion
325: Document xomDoc = DOMConverter.convert(doc);
326: assertEquals(node.getNodeValue(), xomDoc.getValue());
327:
328: }
329:
330: public void testConvertProcessingInstruction() throws SAXException,
331: IOException, ParserConfigurationException {
332:
333: byte[] data = "<element><?target PI data?></element>"
334: .getBytes();
335: org.w3c.dom.Document doc = builder
336: .parse(new ByteArrayInputStream(data));
337:
338: org.w3c.dom.Element root = doc.getDocumentElement();
339: org.w3c.dom.ProcessingInstruction node = (org.w3c.dom.ProcessingInstruction) (root
340: .getChildNodes().item(0));
341: ProcessingInstruction pi = DOMConverter.convert(node);
342: assertEquals(node.getNodeValue(), pi.getValue());
343: assertEquals(node.getTarget(), pi.getTarget());
344:
345: }
346:
347: public void testConvertDocType() throws SAXException, IOException,
348: ParserConfigurationException {
349:
350: byte[] data = "<!DOCTYPE root ><element />".getBytes();
351: org.w3c.dom.Document doc = builder
352: .parse(new ByteArrayInputStream(data));
353:
354: org.w3c.dom.DocumentType type = doc.getDoctype();
355: DocType xomType = DOMConverter.convert(type);
356: assertEquals(type.getName(), xomType.getRootElementName());
357:
358: }
359:
360: public void testConvertInternalDTDSubset() throws SAXException,
361: IOException, ParserConfigurationException {
362:
363: byte[] data = "<!DOCTYPE root [<!ELEMENT element EMPTY>]><element />"
364: .getBytes();
365: org.w3c.dom.Document doc = builder
366: .parse(new ByteArrayInputStream(data));
367:
368: org.w3c.dom.DocumentType type = doc.getDoctype();
369: DocType xomType = DOMConverter.convert(type);
370: assertEquals(type.getName(), xomType.getRootElementName());
371: assertEquals(type.getInternalSubset(), xomType
372: .getInternalDTDSubset());
373:
374: }
375:
376: public void testConvertDocTypePublicAndSystemIdentifier()
377: throws SAXException, IOException,
378: ParserConfigurationException {
379:
380: File inputDir = new File("data");
381: File f = new File(inputDir, "dtdtest.xhtml");
382: org.w3c.dom.Document doc = builder.parse(f);
383:
384: org.w3c.dom.DocumentType type = doc.getDoctype();
385: DocType xomType = DOMConverter.convert(type);
386: assertEquals(type.getName(), xomType.getRootElementName());
387: assertEquals(type.getSystemId(), xomType.getSystemID());
388: assertEquals(type.getPublicId(), xomType.getPublicID());
389:
390: }
391:
392: public void testChildElementAddsNamespace() {
393:
394: Element root = new Element("root");
395: Element child = new Element("pre:child",
396: "http://www.example.org/");
397: child.addAttribute(new Attribute("xlink:type",
398: "http://www.w3.org/1999/xlink", "simple"));
399: root.appendChild(child);
400: Document doc = new Document(root);
401:
402: assertEquals(doc, DOMConverter.convert(DOMConverter.convert(
403: doc, impl)));
404:
405: }
406:
407: public void testChildElementUsesSameNamespace() {
408:
409: Element root = new Element("pre:root",
410: "http://www.example.org/");
411: Element child = new Element("pre:child",
412: "http://www.example.org/");
413: root.appendChild(child);
414: Document doc = new Document(root);
415: assertEquals(doc, DOMConverter.convert(DOMConverter.convert(
416: doc, impl)));
417:
418: }
419:
420: public void testPrefixMappingChanges() {
421:
422: Element root = new Element("pre:root",
423: "http://www.example.org/");
424: Element child = new Element("pre:child",
425: "http://www.example.net/");
426: root.appendChild(child);
427: Document doc = new Document(root);
428: assertEquals(doc, DOMConverter.convert(DOMConverter.convert(
429: doc, impl)));
430:
431: }
432:
433: public void testConvertDocumentFragment() {
434:
435: DocumentFragment fragment = domDocument
436: .createDocumentFragment();
437: org.w3c.dom.Element element = domDocument.createElement("name");
438: element.setAttribute("name", "value");
439: fragment.appendChild(element);
440: fragment.appendChild(domDocument.createComment("data"));
441: fragment.appendChild(domDocument.createTextNode("text"));
442:
443: Nodes result = DOMConverter.convert(fragment);
444:
445: Element first = (Element) result.get(0);
446: assertEquals("name", first.getQualifiedName());
447: assertEquals("name", first.getAttribute("name")
448: .getQualifiedName());
449: assertEquals("value", first.getAttribute("name").getValue());
450:
451: Comment second = (Comment) result.get(1);
452: assertEquals("data", second.getValue());
453:
454: Text third = (Text) result.get(2);
455: assertEquals("text", third.getValue());
456:
457: }
458:
459: // regression found by Wolfgang Hoschek
460: public void testWolfgang() throws ParsingException, IOException {
461:
462: String data = "<m>" + "<a code='3.1415292'>"
463: + "<u>http://www.example.com</u>" + "<h>Some data</h>"
464: + "<s>StockAccess</s>" + "</a>" + "</m>";
465:
466: Document doc = new Builder().build(data, null);
467: Element article = doc.getRootElement().getChildElements()
468: .get(0);
469: Document temp = new Document(new Element(article));
470:
471: org.w3c.dom.Element domArticle = DOMConverter.convert(temp,
472: impl).getDocumentElement();
473: assertEquals(3, domArticle.getChildNodes().getLength());
474: Element out = DOMConverter.convert(domArticle);
475: assertEquals(article, out);
476:
477: }
478:
479: public void testConvertNullXOMDocument() {
480:
481: try {
482: DOMConverter.convert((Document) null, impl);
483: fail("Converted null document");
484: } catch (NullPointerException success) {
485: }
486:
487: }
488:
489: public void testConvertNullDOMElement() {
490:
491: try {
492: DOMConverter.convert((org.w3c.dom.Element) null);
493: fail("Converted null element");
494: } catch (NullPointerException success) {
495: }
496:
497: }
498:
499: public void testConvertNullDOMDocument() {
500:
501: try {
502: DOMConverter.convert((org.w3c.dom.Document) null);
503: fail("Converted null element");
504: } catch (NullPointerException success) {
505: }
506:
507: }
508:
509: /**
510: * Test a bug in a document provided by Wolfgang Hoschek.
511: */
512: public void testFullHoschek() throws ParsingException, IOException {
513:
514: File f = new File("data");
515: f = new File(f, "hoschektest.xml");
516: Builder builder = new Builder();
517: Document xomDocIn = builder.build(f);
518: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
519: impl);
520: Document xomDocOut = DOMConverter.convert(domDoc);
521: assertEquals(xomDocIn, xomDocOut);
522:
523: }
524:
525: /**
526: * Test a bug in identified by Wolfgang Hoschek.
527: */
528: public void testSimplifiedHoschekDOMToXOM() throws SAXException,
529: IOException {
530:
531: File f = new File("data");
532: f = new File(f, "simplehoschektest.xml");
533: org.w3c.dom.Document domDocIn = builder.parse(f);
534: int domRootNumber = domDocIn.getDocumentElement()
535: .getChildNodes().getLength();
536: Document xomDoc = DOMConverter.convert(domDocIn);
537: Element xomRoot = xomDoc.getRootElement();
538: assertEquals(domRootNumber, xomRoot.getChildCount());
539:
540: }
541:
542: public void testChildNodesRemainChildNodes()
543: throws ParsingException, IOException {
544:
545: String data = "<root><scope><a>1</a><b>2</b><c /></scope></root>";
546: Builder builder = new Builder();
547: Document xomDocIn = builder.build(data, null);
548: int xomRootNumber = xomDocIn.getRootElement().getChildCount();
549: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
550: impl);
551: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
552: assertEquals(xomRootNumber, domRoot.getChildNodes().getLength());
553: Document xomDocOut = DOMConverter.convert(domDoc);
554: assertEquals(xomDocIn, xomDocOut);
555:
556: }
557:
558: public void testLastChildNodeIsLeafNode() throws ParsingException,
559: IOException {
560:
561: String data = "<root><top><empty />ABCD</top></root>";
562: Builder builder = new Builder();
563: Document xomDocIn = builder.build(data, null);
564: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
565: impl);
566: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
567: org.w3c.dom.Node domTop = domRoot.getFirstChild();
568: assertEquals(2, domTop.getChildNodes().getLength());
569:
570: }
571:
572: public void testNamespaceAttributes() {
573:
574: Element root = new Element("root", "http://www.example.org/");
575: root.appendChild("text");
576: Document xomDocIn = new Document(root);
577: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
578: impl);
579: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
580: assertTrue(domRoot.hasAttributeNS(
581: "http://www.w3.org/2000/xmlns/", "xmlns"));
582:
583: }
584:
585: public void testConvertSingleElementDocumentFromXOMToDOM() {
586:
587: Element root = new Element("root");
588: Document xomDocIn = new Document(root);
589: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
590: impl);
591: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
592: assertEquals(0, domRoot.getChildNodes().getLength());
593: assertEquals("root", domRoot.getNodeName());
594:
595: }
596:
597: public void testConvertSingleElementDocumentFromDOMToXOM()
598: throws SAXException, IOException {
599:
600: byte[] data = "<element />".getBytes();
601: org.w3c.dom.Document doc = builder
602: .parse(new ByteArrayInputStream(data));
603: Document xomDoc = DOMConverter.convert(doc);
604: Element root = xomDoc.getRootElement();
605: assertEquals(0, root.getChildCount());
606: assertEquals("element", root.getLocalName());
607:
608: }
609:
610: public void testConvertXMLSpaceAttributeFromXOMToDOM()
611: throws SAXException, IOException {
612:
613: Element root = new Element("element");
614: Document doc = new Document(root);
615: root.addAttribute(new Attribute("xml:space",
616: "http://www.w3.org/XML/1998/namespace", "preserve"));
617: org.w3c.dom.Document domDoc = DOMConverter.convert(doc, impl);
618: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
619: assertEquals(1, domRoot.getAttributes().getLength());
620:
621: }
622:
623: public void testConvertXMLPrefixedElementFromXOMToDOM()
624: throws SAXException, IOException {
625:
626: Element root = new Element("xml:element",
627: "http://www.w3.org/XML/1998/namespace");
628: Document doc = new Document(root);
629: org.w3c.dom.Document domDoc = DOMConverter.convert(doc, impl);
630: org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
631: assertEquals(0, domRoot.getAttributes().getLength());
632:
633: }
634:
635: public void testDeepConvert() {
636:
637: Element top = new Element("e");
638: Element parent = top;
639: for (int i = 0; i < 100; i++) {
640: Element child = new Element("e" + i);
641: parent.appendChild(child);
642: parent = child;
643: }
644: Document xomDocIn = new Document(top);
645: org.w3c.dom.Document domDoc = DOMConverter.convert(xomDocIn,
646: impl);
647: Document xomDocOut = DOMConverter.convert(domDoc);
648:
649: assertEquals(xomDocIn, xomDocOut);
650:
651: }
652: }
|