1 #include <QTest>
2 
3 #include <QBuffer>
4 #include <QFile>
5 #include <QDateTime>
6 #include <QProcess>
7 #include <QString>
8 #include <QTextStream>
9 
10 #include <KoXmlReader.h>
11 
12 
13 class TestXmlReaderWithoutSpaces : public QObject
14 {
15     Q_OBJECT
16 private Q_SLOTS:
17     void initTestCase();
18     void testNode();
19     void testElement();
20     void testAttributes();
21     void testText();
22     void testCDATA();
23     void testDocument();
24     void testDocumentType();
25     void testNamespace();
26     void testParseQString();
27     void testUnload();
28     void testSimpleXML();
29     void testRootError();
30     void testMismatchedTag();
31     void testConvertQDomDocument();
32     void testConvertQDomElement();
33     void testSimpleOpenDocumentText();
34     void testWhitespace();
35     void testSimpleOpenDocumentSpreadsheet();
36     void testSimpleOpenDocumentPresentation();
37     void testSimpleOpenDocumentFormula();
38     void testLargeOpenDocumentSpreadsheet();
39     void testExternalOpenDocumentSpreadsheet(const QString& filename);
40 };
41 
initTestCase()42 void TestXmlReaderWithoutSpaces::initTestCase()
43 {
44     QLoggingCategory::setFilterRules("*.debug=false\n"
45     "calligra.lib.odf=true\ncalligra.lib.store=true");
46 }
47 
testNode()48 void TestXmlReaderWithoutSpaces::testNode()
49 {
50     QString errorMsg;
51     int errorLine = 0;
52     int errorColumn = 0;
53 
54     QBuffer xmldevice;
55     xmldevice.open(QIODevice::WriteOnly);
56     QTextStream xmlstream(&xmldevice);
57     xmlstream << "<earth>";
58     xmlstream  << "<continents>";
59     xmlstream   << "<asia/>";
60     xmlstream   << "<africa/>";
61     xmlstream   << "<europe/>";
62     xmlstream   << "<america/>";
63     xmlstream   << "<australia/>";
64     xmlstream   << "<antartic/>";
65     xmlstream  << "</continents>";
66     xmlstream  << "<oceans>";
67     xmlstream   << "<pacific/>";
68     xmlstream   << "<atlantic/>";
69     xmlstream  << "</oceans>";
70     xmlstream << "</earth>";
71     xmldevice.close();
72 
73     KoXmlDocument doc(false);
74     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
75     QCOMPARE(errorMsg.isEmpty(), true);
76     QCOMPARE(errorLine, 0);
77     QCOMPARE(errorColumn, 0);
78 
79     // null node
80     KoXmlNode node1;
81     QCOMPARE(node1.nodeName(), QString());
82     QCOMPARE(node1.isNull(), true);
83     QCOMPARE(node1.isElement(), false);
84     QCOMPARE(node1.isDocument(), false);
85     QCOMPARE(node1.ownerDocument().isNull(), true);
86     QCOMPARE(node1.parentNode().isNull(), true);
87     QCOMPARE(node1.hasChildNodes(), false);
88     QCOMPARE(KoXml::childNodesCount(node1), 0);
89     QCOMPARE(node1.firstChild().isNull(), true);
90     QCOMPARE(node1.lastChild().isNull(), true);
91     QCOMPARE(node1.previousSibling().isNull(), true);
92     QCOMPARE(node1.nextSibling().isNull(), true);
93 
94     // compare with another null node
95     KoXmlNode node2;
96     QCOMPARE(node2.isNull(), true);
97     QCOMPARE(node1 == node2, true);
98     QCOMPARE(node1 != node2, false);
99 
100     // a node which is a document
101     KoXmlNode node3 = doc;
102     QCOMPARE(node3.nodeName(), QString("#document"));
103     QCOMPARE(node3.isNull(), false);
104     QCOMPARE(node3.isElement(), false);
105     QCOMPARE(node3.isText(), false);
106     QCOMPARE(node3.isDocument(), true);
107     QCOMPARE(node3.ownerDocument().isNull(), false);
108     QCOMPARE(node3.ownerDocument() == doc, true);
109     QCOMPARE(node3.toDocument() == doc, true);
110     QCOMPARE(KoXml::childNodesCount(node3), 1);
111 
112     // convert to document and the compare
113     KoXmlDocument doc2 = node3.toDocument();
114     QCOMPARE(doc2.nodeName(), QString("#document"));
115     QCOMPARE(doc2.isNull(), false);
116     QCOMPARE(doc2.isDocument(), true);
117     QCOMPARE(node3 == doc2, true);
118     QCOMPARE(KoXml::childNodesCount(doc2), 1);
119 
120     // a document is of course can't be converted to element
121     KoXmlElement invalidElement = node3.toElement();
122     QCOMPARE(invalidElement.nodeName(), QString());
123     QCOMPARE(invalidElement.isNull(), true);
124     QCOMPARE(invalidElement.isElement(), false);
125     QCOMPARE(invalidElement.isText(), false);
126     QCOMPARE(invalidElement.isDocument(), false);
127 
128     // clear() makes it a null node again
129     node3.clear();
130     QCOMPARE(node3.isNull(), true);
131     QCOMPARE(node3.nodeName(), QString());
132     QCOMPARE(node3.isElement(), false);
133     QCOMPARE(node3.isText(), false);
134     QCOMPARE(node3.isDocument(), false);
135     QCOMPARE(node3.ownerDocument().isNull(), true);
136     QCOMPARE(node1 == node3, true);
137     QCOMPARE(node1 != node3, false);
138 
139     // a node which is an element for <earth>
140     KoXmlNode node4 = doc.firstChild();
141     QCOMPARE(node4.isNull(), false);
142     QCOMPARE(node4.isElement(), true);
143     QCOMPARE(node4.isText(), false);
144     QCOMPARE(node4.isDocument(), false);
145     QCOMPARE(node4.hasChildNodes(), true);
146     QCOMPARE(KoXml::childNodesCount(node4), 2);
147     QCOMPARE(node4.ownerDocument() == doc, true);
148     QCOMPARE(node4.toElement() == doc.firstChild().toElement(), true);
149 
150     // clear() makes it a null node again
151     node4.clear();
152     QCOMPARE(node4.isNull(), true);
153     QCOMPARE(node4.isElement(), false);
154     QCOMPARE(node4.isText(), false);
155     QCOMPARE(node4.isDocument(), false);
156     QCOMPARE(node4 == node1, true);
157     QCOMPARE(node4 != node1, false);
158     QCOMPARE(KoXml::childNodesCount(node4), 0);
159 
160     // a node which is an element for <continents>
161     KoXmlNode node5 = doc.firstChild().firstChild();
162     QCOMPARE(node5.nodeName(), QString("continents"));
163     QCOMPARE(node5.isNull(), false);
164     QCOMPARE(node5.isElement(), true);
165     QCOMPARE(node5.isText(), false);
166     QCOMPARE(node5.isDocument(), false);
167     QCOMPARE(node5.hasChildNodes(), true);
168     QCOMPARE(KoXml::childNodesCount(node5), 6);
169     QCOMPARE(node5.ownerDocument() == doc, true);
170 
171     // convert to element and the compare
172     KoXmlElement continentsElement = node5.toElement();
173     QCOMPARE(node5 == continentsElement, true);
174     QCOMPARE(continentsElement.isNull(), false);
175     QCOMPARE(continentsElement.isElement(), true);
176     QCOMPARE(continentsElement.isText(), false);
177     QCOMPARE(continentsElement.hasChildNodes(), true);
178     QCOMPARE(KoXml::childNodesCount(continentsElement), 6);
179     QCOMPARE(continentsElement.ownerDocument() == doc, true);
180 
181     // and it doesn't make sense to convert that node to document
182     KoXmlDocument invalidDoc = node5.toDocument();
183     QCOMPARE(invalidDoc.isNull(), true);
184     QCOMPARE(invalidDoc.isElement(), false);
185     QCOMPARE(invalidDoc.isText(), false);
186     QCOMPARE(invalidDoc.isDocument(), false);
187 
188     // node for <europe> using namedItem() function
189     KoXmlNode europeNode = continentsElement.namedItem(QString("europe"));
190     QCOMPARE(europeNode.nodeName(), QString("europe"));
191     QCOMPARE(europeNode.isNull(), false);
192     QCOMPARE(europeNode.isElement(), true);
193     QCOMPARE(europeNode.isText(), false);
194     QCOMPARE(europeNode.hasChildNodes(), false);
195     QCOMPARE(KoXml::childNodesCount(europeNode), 0);
196     QCOMPARE(europeNode.ownerDocument() == doc, true);
197 
198     // search non-existing node
199     KoXmlNode fooNode = continentsElement.namedItem(QString("foobar"));
200     QCOMPARE(fooNode.isNull(), true);
201     QCOMPARE(fooNode.isElement(), false);
202     QCOMPARE(fooNode.isText(), false);
203     QCOMPARE(fooNode.isCDATASection(), false);
204     QCOMPARE(KoXml::childNodesCount(fooNode), 0);
205 }
206 
testElement()207 void TestXmlReaderWithoutSpaces::testElement()
208 {
209     QString errorMsg;
210     int errorLine = 0;
211     int errorColumn = 0;
212 
213     QBuffer xmldevice;
214     xmldevice.open(QIODevice::WriteOnly);
215     QTextStream xmlstream(&xmldevice);
216     xmlstream << "<html>";
217     xmlstream << "<body bgcolor=\"#000\">";
218     xmlstream << "<p>";
219     xmlstream << "Hello, world!";
220     xmlstream << "</p>";
221     xmlstream << "</body>";
222     xmlstream << "</html>";
223     xmldevice.close();
224 
225     KoXmlDocument doc(false);
226     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
227     QCOMPARE(errorMsg.isEmpty(), true);
228     QCOMPARE(errorLine, 0);
229     QCOMPARE(errorColumn, 0);
230 
231     // element for <html>
232     KoXmlElement rootElement;
233     rootElement = doc.documentElement();
234     QCOMPARE(rootElement.nodeName(), QString("html"));
235     QCOMPARE(rootElement.isNull(), false);
236     QCOMPARE(rootElement.isElement(), true);
237     QCOMPARE(rootElement.isDocument(), false);
238     QCOMPARE(rootElement.ownerDocument().isNull(), false);
239     QCOMPARE(rootElement.ownerDocument() == doc, true);
240     QCOMPARE(rootElement.parentNode().isNull(), false);
241     QCOMPARE(rootElement.parentNode().toDocument() == doc, true);
242     QCOMPARE(rootElement.hasChildNodes(), true);
243     QCOMPARE(KoXml::childNodesCount(rootElement), 1);
244     QCOMPARE(rootElement.tagName(), QString("html"));
245     QCOMPARE(rootElement.prefix().isNull(), true);
246 
247     // element for <body>
248     KoXmlElement bodyElement;
249     bodyElement = rootElement.firstChild().toElement();
250     QCOMPARE(bodyElement.nodeName(), QString("body"));
251     QCOMPARE(bodyElement.isNull(), false);
252     QCOMPARE(bodyElement.isElement(), true);
253     QCOMPARE(bodyElement.isDocument(), false);
254     QCOMPARE(bodyElement.ownerDocument().isNull(), false);
255     QCOMPARE(bodyElement.ownerDocument() == doc, true);
256     QCOMPARE(bodyElement.parentNode().isNull(), false);
257     QCOMPARE(bodyElement.parentNode() == rootElement, true);
258     QCOMPARE(bodyElement.hasChildNodes(), true);
259     QCOMPARE(KoXml::childNodesCount(bodyElement), 1);
260     QCOMPARE(bodyElement.tagName(), QString("body"));
261     QCOMPARE(bodyElement.prefix().isNull(), true);
262     QCOMPARE(bodyElement.hasAttribute("bgcolor"), true);
263     QCOMPARE(bodyElement.attribute("bgcolor"), QString("#000"));
264 
265     // a shared copy of <body>, will still have access to attribute bgcolor
266     KoXmlElement body2Element;
267     body2Element = bodyElement;
268     QCOMPARE(body2Element.nodeName(), QString("body"));
269     QCOMPARE(body2Element.isNull(), false);
270     QCOMPARE(body2Element.isElement(), true);
271     QCOMPARE(body2Element.isDocument(), false);
272     QCOMPARE(body2Element.ownerDocument().isNull(), false);
273     QCOMPARE(body2Element.ownerDocument() == doc, true);
274     QCOMPARE(body2Element == bodyElement, true);
275     QCOMPARE(body2Element != bodyElement, false);
276     QCOMPARE(body2Element.hasChildNodes(), true);
277     QCOMPARE(KoXml::childNodesCount(body2Element), 1);
278     QCOMPARE(body2Element.tagName(), QString("body"));
279     QCOMPARE(body2Element.prefix().isNull(), true);
280     QCOMPARE(body2Element.hasAttribute("bgcolor"), true);
281     QCOMPARE(body2Element.attribute("bgcolor"), QString("#000"));
282 
283     // empty element, by default constructor
284     KoXmlElement testElement;
285     QCOMPARE(testElement.nodeName(), QString());
286     QCOMPARE(testElement.isNull(), true);
287     QCOMPARE(testElement.isElement(), false);
288     QCOMPARE(testElement.isDocument(), false);
289     QCOMPARE(testElement.ownerDocument().isNull(), true);
290     QCOMPARE(testElement.ownerDocument() != doc, true);
291     QCOMPARE(testElement == rootElement, false);
292     QCOMPARE(testElement != rootElement, true);
293     QCOMPARE(testElement.parentNode().isNull(), true);
294     QCOMPARE(testElement.hasChildNodes(), false);
295     QCOMPARE(KoXml::childNodesCount(testElement), 0);
296 
297     // check assignment operator
298     testElement = rootElement;
299     QCOMPARE(testElement.nodeName(), QString("html"));
300     QCOMPARE(testElement.isNull(), false);
301     QCOMPARE(testElement.isElement(), true);
302     QCOMPARE(testElement.isDocument(), false);
303     QCOMPARE(testElement == rootElement, true);
304     QCOMPARE(testElement != rootElement, false);
305     QCOMPARE(testElement.parentNode().isNull(), false);
306     QCOMPARE(testElement.parentNode().toDocument() == doc, true);
307     QCOMPARE(testElement.tagName(), QString("html"));
308     QCOMPARE(testElement.prefix().isNull(), true);
309     QCOMPARE(KoXml::childNodesCount(testElement), 1);
310 
311     // assigned from another empty element
312     testElement = KoXmlElement();
313     QCOMPARE(testElement.isNull(), true);
314     QCOMPARE(testElement != rootElement, true);
315 
316     // assigned from <body>
317     testElement = bodyElement;
318     QCOMPARE(testElement.isNull(), false);
319     QCOMPARE(testElement.isElement(), true);
320     QCOMPARE(testElement.isDocument(), false);
321     QCOMPARE(testElement.ownerDocument().isNull(), false);
322     QCOMPARE(testElement.ownerDocument() == doc, true);
323     QCOMPARE(testElement == bodyElement, true);
324     QCOMPARE(testElement.parentNode().isNull(), false);
325     QCOMPARE(testElement.tagName(), QString("body"));
326     QCOMPARE(testElement.prefix().isNull(), true);
327     QCOMPARE(testElement.hasChildNodes(), true);
328     QCOMPARE(KoXml::childNodesCount(testElement), 1);
329 
330     // copy constructor
331     KoXmlElement dummyElement(rootElement);
332     QCOMPARE(dummyElement.isNull(), false);
333     QCOMPARE(dummyElement.isElement(), true);
334     QCOMPARE(dummyElement.isDocument(), false);
335     QCOMPARE(dummyElement.ownerDocument().isNull(), false);
336     QCOMPARE(dummyElement.ownerDocument() == doc, true);
337     QCOMPARE(dummyElement == rootElement, true);
338     QCOMPARE(dummyElement.parentNode().isNull(), false);
339     QCOMPARE(dummyElement.hasChildNodes(), true);
340     QCOMPARE(KoXml::childNodesCount(dummyElement), 1);
341     QCOMPARE(dummyElement.tagName(), QString("html"));
342     QCOMPARE(dummyElement.prefix().isNull(), true);
343 
344     // clear() turns element to null node
345     dummyElement.clear();
346     QCOMPARE(dummyElement.isNull(), true);
347     QCOMPARE(dummyElement.isElement(), false);
348     QCOMPARE(dummyElement.isDocument(), false);
349     QCOMPARE(dummyElement.ownerDocument().isNull(), true);
350     QCOMPARE(dummyElement.ownerDocument() == doc, false);
351     QCOMPARE(dummyElement.hasChildNodes(), false);
352     QCOMPARE(KoXml::childNodesCount(dummyElement), 0);
353     QCOMPARE(dummyElement == rootElement, false);
354     QCOMPARE(dummyElement != rootElement, true);
355 
356     // check for plain null node converted to element
357     KoXmlNode dummyNode;
358     dummyElement = dummyNode.toElement();
359     QCOMPARE(dummyElement.isNull(), true);
360     QCOMPARE(dummyElement.isElement(), false);
361     QCOMPARE(dummyElement.isDocument(), false);
362     QCOMPARE(dummyElement.ownerDocument().isNull(), true);
363     QCOMPARE(dummyElement.hasChildNodes(), false);
364     QCOMPARE(KoXml::childNodesCount(dummyElement), 0);
365     QCOMPARE(dummyElement.ownerDocument() == doc, false);
366 }
367 
testAttributes()368 void TestXmlReaderWithoutSpaces::testAttributes()
369 {
370     QString errorMsg;
371     int errorLine = 0;
372     int errorColumn = 0;
373 
374     QBuffer xmldevice;
375     xmldevice.open(QIODevice::WriteOnly);
376     QTextStream xmlstream(&xmldevice);
377     xmlstream << "<p>";
378     xmlstream << "<img src=\"foo.png\" width=\"300\" height=\"150\"/>";
379     xmlstream << "</p>";
380     xmldevice.close();
381 
382     KoXmlDocument doc(false);
383     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
384     QCOMPARE(errorMsg.isEmpty(), true);
385     QCOMPARE(errorLine, 0);
386     QCOMPARE(errorColumn, 0);
387 
388     KoXmlElement rootElement;
389     rootElement = doc.documentElement();
390     QCOMPARE(rootElement.isNull(), false);
391     QCOMPARE(rootElement.isElement(), true);
392     QCOMPARE(rootElement.parentNode().isNull(), false);
393     QCOMPARE(rootElement.parentNode().toDocument() == doc, true);
394     QCOMPARE(rootElement.tagName(), QString("p"));
395     QCOMPARE(rootElement.prefix().isNull(), true);
396     QCOMPARE(KoXml::childNodesCount(rootElement), 1);
397 
398     KoXmlElement imgElement;
399     imgElement = rootElement.firstChild().toElement();
400     QCOMPARE(imgElement.isNull(), false);
401     QCOMPARE(imgElement.isElement(), true);
402     QCOMPARE(imgElement.tagName(), QString("img"));
403     QCOMPARE(imgElement.prefix().isNull(), true);
404     QCOMPARE(KoXml::childNodesCount(imgElement), 0);
405     QCOMPARE(imgElement.hasAttribute("src"), true);
406     QCOMPARE(imgElement.hasAttribute("width"), true);
407     QCOMPARE(imgElement.hasAttribute("height"), true);
408     QCOMPARE(imgElement.hasAttribute("non-exist"), false);
409     QCOMPARE(imgElement.hasAttribute("SRC"), false);
410     QCOMPARE(imgElement.attribute("src"), QString("foo.png"));
411     QCOMPARE(imgElement.attribute("width"), QString("300"));
412     QCOMPARE(imgElement.attribute("width").toInt(), 300);
413     QCOMPARE(imgElement.attribute("height"), QString("150"));
414     QCOMPARE(imgElement.attribute("height").toInt(), 150);
415     QCOMPARE(imgElement.attribute("border").isEmpty(), true);
416     QCOMPARE(imgElement.attribute("border", "0").toInt(), 0);
417     QCOMPARE(imgElement.attribute("border", "-1").toInt(), -1);
418 
419     QStringList list = KoXml::attributeNames(imgElement);
420     QCOMPARE(list.count(), 3);
421     QVERIFY(list.contains("src"));
422     QVERIFY(list.contains("width"));
423     QVERIFY(list.contains("height"));
424     QVERIFY(! list.contains("border"));
425     foreach(QString a, list) {
426         QCOMPARE(imgElement.hasAttribute(a), true);
427         QCOMPARE(imgElement.attribute(a).isEmpty(), false);
428     }
429 }
430 
testText()431 void TestXmlReaderWithoutSpaces::testText()
432 {
433     QString errorMsg;
434     int errorLine = 0;
435     int errorColumn = 0;
436 
437     QBuffer xmldevice;
438     xmldevice.open(QIODevice::WriteOnly);
439     QTextStream xmlstream(&xmldevice);
440     xmlstream << "<p>";
441     xmlstream << "Hello ";
442     xmlstream << "<b>world</b>";
443     xmlstream << "</p>";
444     xmldevice.close();
445 
446     KoXmlDocument doc(false);
447     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
448     QCOMPARE(errorMsg.isEmpty(), true);
449     QCOMPARE(errorLine, 0);
450     QCOMPARE(errorColumn, 0);
451 
452     // element for <p>
453     KoXmlElement parElement;
454     parElement = doc.documentElement();
455     QCOMPARE(parElement.isNull(), false);
456     QCOMPARE(parElement.isElement(), true);
457     QCOMPARE(parElement.isText(), false);
458     QCOMPARE(parElement.isDocument(), false);
459     QCOMPARE(parElement.ownerDocument().isNull(), false);
460     QCOMPARE(parElement.ownerDocument() == doc, true);
461     QCOMPARE(parElement.parentNode().isNull(), false);
462     QCOMPARE(parElement.parentNode().toDocument() == doc, true);
463     QCOMPARE(parElement.hasChildNodes(), true);
464     QCOMPARE(KoXml::childNodesCount(parElement), 2);   // <b> and text node "Hello "
465     QCOMPARE(parElement.tagName(), QString("p"));
466     QCOMPARE(parElement.prefix().isNull(), true);
467     QCOMPARE(parElement.text(), QString("Hello world"));
468 
469     // node for "Hello"
470     KoXmlNode helloNode;
471     helloNode = parElement.firstChild();
472     QCOMPARE(helloNode.nodeName(), QString("#text"));
473     QCOMPARE(helloNode.isNull(), false);
474     QCOMPARE(helloNode.isElement(), false);
475     QCOMPARE(helloNode.isText(), true);
476     QCOMPARE(helloNode.isDocument(), false);
477     QCOMPARE(helloNode.hasChildNodes(), false);
478     QCOMPARE(KoXml::childNodesCount(helloNode), 0);
479 
480     // "Hello" text
481     KoXmlText helloText;
482     helloText = helloNode.toText();
483     QCOMPARE(helloText.nodeName(), QString("#text"));
484     QCOMPARE(helloText.isNull(), false);
485     QCOMPARE(helloText.isElement(), false);
486     QCOMPARE(helloText.isText(), true);
487     QCOMPARE(helloText.isDocument(), false);
488     QCOMPARE(helloText.data(), QString("Hello "));
489     QCOMPARE(KoXml::childNodesCount(helloText), 0);
490 
491     // shared copy of the text
492     KoXmlText hello2Text;
493     hello2Text = helloText;
494     QCOMPARE(hello2Text.isNull(), false);
495     QCOMPARE(hello2Text.isElement(), false);
496     QCOMPARE(hello2Text.isText(), true);
497     QCOMPARE(hello2Text.isDocument(), false);
498     QCOMPARE(hello2Text.data(), QString("Hello "));
499     QCOMPARE(KoXml::childNodesCount(hello2Text), 0);
500 
501     // element for <b>
502     KoXmlElement boldElement;
503     boldElement = helloNode.nextSibling().toElement();
504     QCOMPARE(boldElement.isNull(), false);
505     QCOMPARE(boldElement.isElement(), true);
506     QCOMPARE(boldElement.isText(), false);
507     QCOMPARE(boldElement.isDocument(), false);
508     QCOMPARE(boldElement.ownerDocument().isNull(), false);
509     QCOMPARE(boldElement.ownerDocument() == doc, true);
510     QCOMPARE(boldElement.parentNode().isNull(), false);
511     QCOMPARE(boldElement.hasChildNodes(), true);
512     QCOMPARE(KoXml::childNodesCount(boldElement), 1);   // text node "world"
513     QCOMPARE(boldElement.tagName(), QString("b"));
514     QCOMPARE(boldElement.prefix().isNull(), true);
515 
516     // "world" text
517     KoXmlText worldText;
518     worldText = boldElement.firstChild().toText();
519     QCOMPARE(worldText.isNull(), false);
520     QCOMPARE(worldText.isElement(), false);
521     QCOMPARE(worldText.isText(), true);
522     QCOMPARE(worldText.isDocument(), false);
523     QCOMPARE(worldText.data(), QString("world"));
524     QCOMPARE(KoXml::childNodesCount(worldText), 0);
525 }
526 
testCDATA()527 void TestXmlReaderWithoutSpaces::testCDATA()
528 {
529     QString errorMsg;
530     int errorLine = 0;
531     int errorColumn = 0;
532 
533     QBuffer xmldevice;
534     xmldevice.open(QIODevice::WriteOnly);
535     QTextStream xmlstream(&xmldevice);
536     xmlstream << "<p>";
537     xmlstream << "Hello ";
538     xmlstream << "<![CDATA[world]]>";
539     xmlstream << "</p>";
540     xmldevice.close();
541 
542     KoXmlDocument doc(false);
543     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
544     QCOMPARE(errorMsg.isEmpty(), true);
545     QCOMPARE(errorLine, 0);
546     QCOMPARE(errorColumn, 0);
547 
548     // element for <p>
549     KoXmlElement parElement;
550     parElement = doc.documentElement();
551     QCOMPARE(parElement.isNull(), false);
552     QCOMPARE(parElement.isElement(), true);
553     QCOMPARE(parElement.isText(), false);
554     QCOMPARE(parElement.isDocument(), false);
555     QCOMPARE(parElement.ownerDocument().isNull(), false);
556     QCOMPARE(parElement.ownerDocument() == doc, true);
557     QCOMPARE(parElement.parentNode().isNull(), false);
558     QCOMPARE(parElement.parentNode().toDocument() == doc, true);
559     QCOMPARE(parElement.hasChildNodes(), true);
560     QCOMPARE(KoXml::childNodesCount(parElement), 2);
561     QCOMPARE(parElement.tagName(), QString("p"));
562     QCOMPARE(parElement.prefix().isNull(), true);
563     QCOMPARE(parElement.text(), QString("Hello world"));
564 
565     // node for "Hello"
566     KoXmlNode helloNode;
567     helloNode = parElement.firstChild();
568     QCOMPARE(helloNode.isNull(), false);
569     QCOMPARE(helloNode.isElement(), false);
570     QCOMPARE(helloNode.isText(), true);
571     QCOMPARE(helloNode.isDocument(), false);
572 
573     // "Hello" text
574     KoXmlText helloText;
575     helloText = helloNode.toText();
576     QCOMPARE(helloText.isNull(), false);
577     QCOMPARE(helloText.isElement(), false);
578     QCOMPARE(helloText.isText(), true);
579     QCOMPARE(helloText.isDocument(), false);
580     QCOMPARE(helloText.data(), QString("Hello "));
581 
582     // node for CDATA "world!"
583     // Note: isText() is also true for CDATA
584     KoXmlNode worldNode;
585     worldNode = helloNode.nextSibling();
586     QCOMPARE(worldNode.nodeName(), QString("#cdata-section"));
587     QCOMPARE(worldNode.isNull(), false);
588     QCOMPARE(worldNode.isElement(), false);
589     QCOMPARE(worldNode.isText(), true);
590     QCOMPARE(worldNode.isCDATASection(), true);
591     QCOMPARE(worldNode.isDocument(), false);
592 
593     // CDATA section for "world!"
594     // Note: isText() is also true for CDATA
595     KoXmlCDATASection worldCDATA;
596     worldCDATA = worldNode.toCDATASection();
597     QCOMPARE(worldCDATA.nodeName(), QString("#cdata-section"));
598     QCOMPARE(worldCDATA.isNull(), false);
599     QCOMPARE(worldCDATA.isElement(), false);
600     QCOMPARE(worldCDATA.isText(), true);
601     QCOMPARE(worldCDATA.isCDATASection(), true);
602     QCOMPARE(worldCDATA.isDocument(), false);
603     QCOMPARE(worldCDATA.data(), QString("world"));
604 }
605 
testDocument()606 void TestXmlReaderWithoutSpaces::testDocument()
607 {
608     QString errorMsg;
609     int errorLine = 0;
610     int errorColumn = 0;
611 
612     QBuffer xmldevice;
613     xmldevice.open(QIODevice::WriteOnly);
614     QTextStream xmlstream(&xmldevice);
615     xmlstream << "<calligra>";
616     xmlstream   << "<words/>\n";
617     xmlstream   << "<stage/>\n";
618     xmlstream << "</calligra>";
619     xmldevice.close();
620 
621     KoXmlDocument doc(false);
622 
623     // empty document
624     QCOMPARE(doc.nodeName(), QString());
625     QCOMPARE(doc.isNull(), true);
626     QCOMPARE(doc.isElement(), false);
627     QCOMPARE(doc.isDocument(), false);
628     QCOMPARE(doc.parentNode().isNull(), true);
629     QCOMPARE(doc.firstChild().isNull(), true);
630     QCOMPARE(doc.lastChild().isNull(), true);
631     QCOMPARE(doc.previousSibling().isNull(), true);
632     QCOMPARE(doc.nextSibling().isNull(), true);
633 
634     // now give something as the content
635     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
636     QCOMPARE(errorMsg.isEmpty(), true);
637     QCOMPARE(errorLine, 0);
638     QCOMPARE(errorColumn, 0);
639 
640     // this document has something already
641     QCOMPARE(doc.nodeName(), QString("#document"));
642     QCOMPARE(doc.isNull(), false);
643     QCOMPARE(doc.isElement(), false);
644     QCOMPARE(doc.isDocument(), true);
645     QCOMPARE(doc.parentNode().isNull(), true);
646     QCOMPARE(doc.firstChild().isNull(), false);
647     QCOMPARE(doc.lastChild().isNull(), false);
648     QCOMPARE(doc.previousSibling().isNull(), true);
649     QCOMPARE(doc.nextSibling().isNull(), true);
650 
651     // make sure its children are fine
652     KoXmlElement rootElement;
653     rootElement = doc.firstChild().toElement();
654     QCOMPARE(rootElement.isNull(), false);
655     QCOMPARE(rootElement.isElement(), true);
656     QCOMPARE(rootElement.isDocument(), false);
657     QCOMPARE(rootElement.parentNode().isNull(), false);
658     QCOMPARE(rootElement.parentNode().toDocument() == doc, true);
659     rootElement = doc.lastChild().toElement();
660     QCOMPARE(rootElement.isNull(), false);
661     QCOMPARE(rootElement.isElement(), true);
662     QCOMPARE(rootElement.isDocument(), false);
663     QCOMPARE(rootElement.parentNode().isNull(), false);
664     QCOMPARE(rootElement.parentNode().toDocument() == doc, true);
665 
666     // clear() converts it into null node
667     doc.clear();
668     QCOMPARE(doc.nodeName(), QString());
669     QCOMPARE(doc.isNull(), true);
670     QCOMPARE(doc.isElement(), false);
671     QCOMPARE(doc.isDocument(), false);
672     QCOMPARE(doc.parentNode().isNull(), true);
673     QCOMPARE(doc.firstChild().isNull(), true);
674     QCOMPARE(doc.lastChild().isNull(), true);
675     QCOMPARE(doc.previousSibling().isNull(), true);
676     QCOMPARE(doc.nextSibling().isNull(), true);
677 
678     // assigned from another empty document
679     doc = KoXmlDocument();
680     QCOMPARE(doc.nodeName(), QString());
681     QCOMPARE(doc.nodeName().isEmpty(), true);
682     QCOMPARE(doc.isNull(), true);
683     QCOMPARE(doc.isElement(), false);
684     QCOMPARE(doc.isDocument(), false);
685     QCOMPARE(doc.parentNode().isNull(), true);
686 }
687 
testDocumentType()688 void TestXmlReaderWithoutSpaces::testDocumentType()
689 {
690     QString errorMsg;
691     int errorLine = 0;
692     int errorColumn = 0;
693 
694     QBuffer xmldevice;
695     xmldevice.open(QIODevice::WriteOnly);
696     QTextStream xmlstream(&xmldevice);
697     xmlstream << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
698     xmlstream << "<body>";
699     xmlstream   << "<img/>";
700     xmlstream   << "<p/>";
701     xmlstream   << "<blockquote/>";
702     xmlstream << "</body>";
703     xmldevice.close();
704 
705     // empty document
706     KoXmlDocument doc(false);
707     QCOMPARE(doc.nodeName(), QString());
708     QCOMPARE(doc.isNull(), true);
709     QCOMPARE(doc.isElement(), false);
710     QCOMPARE(doc.isDocument(), false);
711     QCOMPARE(doc.parentNode().isNull(), true);
712     QCOMPARE(doc.firstChild().isNull(), true);
713     QCOMPARE(doc.lastChild().isNull(), true);
714     QCOMPARE(doc.previousSibling().isNull(), true);
715     QCOMPARE(doc.nextSibling().isNull(), true);
716 
717     // has empty doctype
718     KoXmlDocumentType doctype = doc.doctype();
719     QCOMPARE(doctype.nodeName(), QString());
720     QCOMPARE(doctype.isNull(), true);
721     QCOMPARE(doctype.isElement(), false);
722     QCOMPARE(doctype.isDocument(), false);
723     QCOMPARE(doctype.isDocumentType(), false);
724     QCOMPARE(doctype.parentNode().isNull(), true);
725     QCOMPARE(doctype.firstChild().isNull(), true);
726     QCOMPARE(doctype.lastChild().isNull(), true);
727     QCOMPARE(doctype.previousSibling().isNull(), true);
728     QCOMPARE(doctype.nextSibling().isNull(), true);
729 
730     // now give something as the content
731     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
732     QCOMPARE(errorMsg.isEmpty(), true);
733     QCOMPARE(errorLine, 0);
734     QCOMPARE(errorColumn, 0);
735 
736     // this document has something already
737     QCOMPARE(doc.nodeName(), QString("#document"));
738     QCOMPARE(doc.isNull(), false);
739     QCOMPARE(doc.isElement(), false);
740     QCOMPARE(doc.isDocument(), true);
741     QCOMPARE(doc.parentNode().isNull(), true);
742     QCOMPARE(doc.firstChild().isNull(), false);
743     QCOMPARE(doc.lastChild().isNull(), false);
744     QCOMPARE(doc.previousSibling().isNull(), true);
745     QCOMPARE(doc.nextSibling().isNull(), true);
746 
747     // the doctype becomes a valid one
748     doctype = doc.doctype();
749     QCOMPARE(doctype.nodeName(), QString("html"));
750     QCOMPARE(doctype.name(), QString("html"));
751     QCOMPARE(doctype.isNull(), false);
752     QCOMPARE(doctype.isElement(), false);
753     QCOMPARE(doctype.isDocument(), false);
754     QCOMPARE(doctype.isDocumentType(), true);
755     QCOMPARE(doctype.parentNode().isNull(), false);
756     QCOMPARE(doctype.parentNode() == doc, true);
757     QCOMPARE(doctype.firstChild().isNull(), true);
758     QCOMPARE(doctype.lastChild().isNull(), true);
759     QCOMPARE(doctype.previousSibling().isNull(), true);
760     QCOMPARE(doctype.nextSibling().isNull(), true);
761 }
762 
testNamespace()763 void TestXmlReaderWithoutSpaces::testNamespace()
764 {
765     QString errorMsg;
766     int errorLine = 0;
767     int errorColumn = 0;
768 
769     QBuffer xmldevice;
770     xmldevice.open(QIODevice::WriteOnly);
771     QTextStream xmlstream(&xmldevice);
772 
773     // taken from example in Qt documentation (xml.html)
774     xmlstream << "<document xmlns:book = \"http://trolltech.com/fnord/book/\"";
775     xmlstream << "          xmlns      = \"http://trolltech.com/fnord/\" >";
776     xmlstream << "<book>";
777     xmlstream   << "<book:title>Practical XML</book:title>";
778     xmlstream   << "<book:author xmlns:fnord = \"http://trolltech.com/fnord/\"";
779     xmlstream   << "             title=\"Ms\"";
780     xmlstream   << "             fnord:title=\"Goddess\"";
781     xmlstream   << "             name=\"Eris Kallisti\"/>";
782     xmlstream   << "<chapter>";
783     xmlstream     << "<title>A Namespace Called fnord</title>";
784     xmlstream   << "</chapter>";
785     xmlstream << "</book>";
786     xmlstream << "</document>";
787     xmldevice.close();
788 
789     KoXmlDocument doc(false);
790     KoXmlElement rootElement;
791     KoXmlElement bookElement;
792     KoXmlElement bookTitleElement;
793     KoXmlElement bookAuthorElement;
794 
795     // ------------- first without any namespace processing -----------
796     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
797     QCOMPARE(errorMsg.isEmpty(), true);
798     QCOMPARE(errorLine, 0);
799     QCOMPARE(errorColumn, 0);
800 
801     rootElement = doc.documentElement();
802     QCOMPARE(rootElement.isNull(), false);
803     QCOMPARE(rootElement.isElement(), true);
804     QCOMPARE(rootElement.tagName(), QString("document"));
805     QCOMPARE(rootElement.prefix().isNull(), true);
806 
807     bookElement = rootElement.firstChild().toElement();
808     QCOMPARE(bookElement.isNull(), false);
809     QCOMPARE(bookElement.isElement(), true);
810     QCOMPARE(bookElement.tagName(), QString("book"));
811     QCOMPARE(bookElement.prefix().isNull(), true);
812     QCOMPARE(bookElement.localName(), QString());
813 
814     bookTitleElement = bookElement.firstChild().toElement();
815     QCOMPARE(bookTitleElement.isNull(), false);
816     QCOMPARE(bookTitleElement.isElement(), true);
817     QCOMPARE(bookTitleElement.tagName(), QString("book:title"));
818     QCOMPARE(bookTitleElement.prefix().isNull(), true);
819     QCOMPARE(bookTitleElement.localName(), QString());
820 
821     bookAuthorElement = bookTitleElement.nextSibling().toElement();
822     QCOMPARE(bookAuthorElement.isNull(), false);
823     QCOMPARE(bookAuthorElement.isElement(), true);
824     QCOMPARE(bookAuthorElement.tagName(), QString("book:author"));
825     QCOMPARE(bookAuthorElement.prefix().isNull(), true);
826     QCOMPARE(bookAuthorElement.attribute("title"), QString("Ms"));
827     QCOMPARE(bookAuthorElement.attribute("fnord:title"), QString("Goddess"));
828     QCOMPARE(bookAuthorElement.attribute("name"), QString("Eris Kallisti"));
829 
830     // ------------- now with namespace processing -----------
831     xmldevice.seek(0); // just to rewind
832 
833     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
834     QCOMPARE(errorMsg.isEmpty(), true);
835     QCOMPARE(errorLine, 0);
836     QCOMPARE(errorColumn, 0);
837 
838     const char* defaultNS = "http://trolltech.com/fnord/";
839     const char* bookNS = "http://trolltech.com/fnord/book/";
840     const char* fnordNS = "http://trolltech.com/fnord/";
841 
842     // <document>
843     rootElement = doc.documentElement();
844     QCOMPARE(rootElement.isNull(), false);
845     QCOMPARE(rootElement.isElement(), true);
846     QCOMPARE(rootElement.tagName(), QString("document"));
847     QCOMPARE(rootElement.prefix().isEmpty(), true);
848     QCOMPARE(rootElement.namespaceURI(), QString(defaultNS));
849     QCOMPARE(rootElement.localName(), QString("document"));
850 
851     // <book>
852     bookElement = rootElement.firstChild().toElement();
853     QCOMPARE(bookElement.isNull(), false);
854     QCOMPARE(bookElement.isElement(), true);
855     QCOMPARE(bookElement.tagName(), QString("book"));
856     QCOMPARE(bookElement.prefix().isEmpty(), true);
857     QCOMPARE(bookElement.namespaceURI(), QString(defaultNS));
858     QCOMPARE(bookElement.localName(), QString("book"));
859 
860     // <book:title>
861     bookTitleElement = bookElement.firstChild().toElement();
862     QCOMPARE(bookTitleElement.isNull(), false);
863     QCOMPARE(bookTitleElement.isElement(), true);
864     QCOMPARE(bookTitleElement.tagName(), QString("title"));
865     QCOMPARE(bookTitleElement.prefix(), QString("book"));
866     QCOMPARE(bookTitleElement.namespaceURI(), QString(bookNS));
867     QCOMPARE(bookTitleElement.localName(), QString("title"));
868 
869     // another way, find it using namedItemNS()
870     KoXmlElement book2TitleElement;
871     book2TitleElement = KoXml::namedItemNS(rootElement.firstChild(), bookNS, "title");
872     //book2TitleElement = bookElement.namedItemNS( bookNS, "title" ).toElement();
873     QCOMPARE(book2TitleElement == bookTitleElement, true);
874     QCOMPARE(book2TitleElement.isNull(), false);
875     QCOMPARE(book2TitleElement.isElement(), true);
876     QCOMPARE(book2TitleElement.tagName(), QString("title"));
877 
878     // <book:author>
879     bookAuthorElement = bookTitleElement.nextSibling().toElement();
880     QCOMPARE(bookAuthorElement.isNull(), false);
881     QCOMPARE(bookAuthorElement.isElement(), true);
882     QCOMPARE(bookAuthorElement.tagName(), QString("author"));
883     QCOMPARE(bookAuthorElement.prefix(), QString("book"));
884     QCOMPARE(bookAuthorElement.namespaceURI(), QString(bookNS));
885     QCOMPARE(bookAuthorElement.localName(), QString("author"));
886 
887     // another way, find it using namedItemNS()
888     KoXmlElement book2AuthorElement;
889     book2AuthorElement = KoXml::namedItemNS(bookElement, bookNS, "author");
890     //book2AuthorElement = bookElement.namedItemNS( bookNS, "author" ).toElement();
891     QCOMPARE(book2AuthorElement == bookAuthorElement, true);
892     QCOMPARE(book2AuthorElement.isNull(), false);
893     QCOMPARE(book2AuthorElement.isElement(), true);
894     QCOMPARE(book2AuthorElement.tagName(), QString("author"));
895 
896     // attributes in <book:author>
897     // Note: with namespace processing, attribute's prefix is taken out and
898     // hence "fnord:title" will simply override "title"
899     // and searching attribute with prefix will give no result
900     QCOMPARE(bookAuthorElement.hasAttribute("title"), true);
901     QCOMPARE(bookAuthorElement.hasAttribute("fnord:title"), false);
902     QCOMPARE(bookAuthorElement.hasAttribute("name"), true);
903     QCOMPARE(bookAuthorElement.attribute("title"), QString("Goddess"));
904     QCOMPARE(bookAuthorElement.attribute("fnord:title").isEmpty(), true);
905     QCOMPARE(bookAuthorElement.attribute("name"), QString("Eris Kallisti"));
906 
907     // attributes in <book:author>, with NS family of functions
908     // those without prefix are not accessible at all, because they do not belong
909     // to any namespace at all.
910     // Note: default namespace does not apply to attribute names!
911     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "title"), true);
912     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "title"), false);
913     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "title"), true);
914 
915     QCOMPARE(bookAuthorElement.attributeNS(defaultNS, "title", ""), QString("Goddess"));
916     QCOMPARE(bookAuthorElement.attributeNS(bookNS, "title", ""), QString(""));
917     QCOMPARE(bookAuthorElement.attributeNS(fnordNS, "title", ""), QString("Goddess"));
918 
919     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "fnord:title"), false);
920     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "fnord:title"), false);
921     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "fnord:title"), false);
922 
923     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "name"), false);
924     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "name"), false);
925     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "name"), false);
926 
927     QCOMPARE(bookAuthorElement.attributeNS(defaultNS, "name", QString()).isEmpty(), true);
928     QCOMPARE(bookAuthorElement.attributeNS(bookNS, "name", QString()).isEmpty(), true);
929     QCOMPARE(bookAuthorElement.attributeNS(fnordNS, "name", QString()).isEmpty(), true);
930 }
931 
932 // mostly similar to testNamespace above, but parse from a QString
testParseQString()933 void TestXmlReaderWithoutSpaces::testParseQString()
934 {
935     QString errorMsg;
936     int errorLine = 0;
937     int errorColumn = 0;
938 
939     QString xmlText;
940     xmlText +=  "<document xmlns:book = \"http://trolltech.com/fnord/book/\"";
941     xmlText +=  "          xmlns      = \"http://trolltech.com/fnord/\" >";
942     xmlText +=  "<book>";
943     xmlText   +=  "<book:title>Practical XML</book:title>";
944     xmlText   +=  "<book:author xmlns:fnord = \"http://trolltech.com/fnord/\"";
945     xmlText   +=  "             title=\"Ms\"";
946     xmlText   +=  "             fnord:title=\"Goddess\"";
947     xmlText   +=  "             name=\"Eris Kallisti\"/>";
948     xmlText   +=  "<chapter>";
949     xmlText     +=  "<title>A Namespace Called fnord</title>";
950     xmlText   +=  "</chapter>";
951     xmlText +=  "</book>";
952     xmlText +=  "</document>";
953 
954     KoXmlDocument doc(false);
955     KoXmlElement rootElement;
956     KoXmlElement bookElement;
957     KoXmlElement bookTitleElement;
958     KoXmlElement bookAuthorElement;
959 
960     QCOMPARE(doc.setContent(xmlText, true, &errorMsg, &errorLine, &errorColumn), true);
961     QCOMPARE(errorMsg.isEmpty(), true);
962     QCOMPARE(errorLine, 0);
963     QCOMPARE(errorColumn, 0);
964 
965     const char* defaultNS = "http://trolltech.com/fnord/";
966     const char* bookNS = "http://trolltech.com/fnord/book/";
967     const char* fnordNS = "http://trolltech.com/fnord/";
968 
969     // <document>
970     rootElement = doc.documentElement();
971     QCOMPARE(rootElement.isNull(), false);
972     QCOMPARE(rootElement.isElement(), true);
973     QCOMPARE(rootElement.tagName(), QString("document"));
974     QCOMPARE(rootElement.prefix().isEmpty(), true);
975     QCOMPARE(rootElement.namespaceURI(), QString(defaultNS));
976     QCOMPARE(rootElement.localName(), QString("document"));
977 
978     // <book>
979     bookElement = rootElement.firstChild().toElement();
980     QCOMPARE(bookElement.isNull(), false);
981     QCOMPARE(bookElement.isElement(), true);
982     QCOMPARE(bookElement.tagName(), QString("book"));
983     QCOMPARE(bookElement.prefix().isEmpty(), true);
984     QCOMPARE(bookElement.namespaceURI(), QString(defaultNS));
985     QCOMPARE(bookElement.localName(), QString("book"));
986 
987     // <book:title>
988     bookTitleElement = bookElement.firstChild().toElement();
989     QCOMPARE(bookTitleElement.isNull(), false);
990     QCOMPARE(bookTitleElement.isElement(), true);
991     QCOMPARE(bookTitleElement.tagName(), QString("title"));
992     QCOMPARE(bookTitleElement.prefix(), QString("book"));
993     QCOMPARE(bookTitleElement.namespaceURI(), QString(bookNS));
994     QCOMPARE(bookTitleElement.localName(), QString("title"));
995 
996     // another way, find it using namedItemNS()
997     KoXmlElement book2TitleElement;
998     book2TitleElement = KoXml::namedItemNS(rootElement.firstChild(), bookNS, "title");
999     //book2TitleElement = bookElement.namedItemNS( bookNS, "title" ).toElement();
1000     QCOMPARE(book2TitleElement == bookTitleElement, true);
1001     QCOMPARE(book2TitleElement.isNull(), false);
1002     QCOMPARE(book2TitleElement.isElement(), true);
1003     QCOMPARE(book2TitleElement.tagName(), QString("title"));
1004 
1005     // <book:author>
1006     bookAuthorElement = bookTitleElement.nextSibling().toElement();
1007     QCOMPARE(bookAuthorElement.isNull(), false);
1008     QCOMPARE(bookAuthorElement.isElement(), true);
1009     QCOMPARE(bookAuthorElement.tagName(), QString("author"));
1010     QCOMPARE(bookAuthorElement.prefix(), QString("book"));
1011     QCOMPARE(bookAuthorElement.namespaceURI(), QString(bookNS));
1012     QCOMPARE(bookAuthorElement.localName(), QString("author"));
1013 
1014     // another way, find it using namedItemNS()
1015     KoXmlElement book2AuthorElement;
1016     book2AuthorElement = KoXml::namedItemNS(bookElement, bookNS, "author");
1017     //book2AuthorElement = bookElement.namedItemNS( bookNS, "author" ).toElement();
1018     QCOMPARE(book2AuthorElement == bookAuthorElement, true);
1019     QCOMPARE(book2AuthorElement.isNull(), false);
1020     QCOMPARE(book2AuthorElement.isElement(), true);
1021     QCOMPARE(book2AuthorElement.tagName(), QString("author"));
1022 
1023     // attributes in <book:author>
1024     // Note: with namespace processing, attribute's prefix is taken out and
1025     // hence "fnord:title" will simply override "title"
1026     // and searching attribute with prefix will give no result
1027     QCOMPARE(bookAuthorElement.hasAttribute("title"), true);
1028     QCOMPARE(bookAuthorElement.hasAttribute("fnord:title"), false);
1029     QCOMPARE(bookAuthorElement.hasAttribute("name"), true);
1030     QCOMPARE(bookAuthorElement.attribute("title"), QString("Goddess"));
1031     QCOMPARE(bookAuthorElement.attribute("fnord:title").isEmpty(), true);
1032     QCOMPARE(bookAuthorElement.attribute("name"), QString("Eris Kallisti"));
1033 
1034     // attributes in <book:author>, with NS family of functions
1035     // those without prefix are not accessible at all, because they do not belong
1036     // to any namespace at all.
1037     // Note: default namespace does not apply to attribute names!
1038     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "title"), true);
1039     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "title"), false);
1040     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "title"), true);
1041 
1042     QCOMPARE(bookAuthorElement.attributeNS(defaultNS, "title", ""), QString("Goddess"));
1043     QCOMPARE(bookAuthorElement.attributeNS(bookNS, "title", ""), QString(""));
1044     QCOMPARE(bookAuthorElement.attributeNS(fnordNS, "title", ""), QString("Goddess"));
1045 
1046     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "fnord:title"), false);
1047     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "fnord:title"), false);
1048     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "fnord:title"), false);
1049 
1050     QCOMPARE(bookAuthorElement.hasAttributeNS(defaultNS, "name"), false);
1051     QCOMPARE(bookAuthorElement.hasAttributeNS(bookNS, "name"), false);
1052     QCOMPARE(bookAuthorElement.hasAttributeNS(fnordNS, "name"), false);
1053 
1054     QCOMPARE(bookAuthorElement.attributeNS(defaultNS, "name", QString()).isEmpty(), true);
1055     QCOMPARE(bookAuthorElement.attributeNS(bookNS, "name", QString()).isEmpty(), true);
1056     QCOMPARE(bookAuthorElement.attributeNS(fnordNS, "name", QString()).isEmpty(), true);
1057 }
1058 
testUnload()1059 void TestXmlReaderWithoutSpaces::testUnload()
1060 {
1061     QString errorMsg;
1062     int errorLine = 0;
1063     int errorColumn = 0;
1064 
1065     QBuffer xmldevice;
1066     xmldevice.open(QIODevice::WriteOnly);
1067     QTextStream xmlstream(&xmldevice);
1068 
1069     xmlstream << "<earth>";
1070     xmlstream << "<continents>";
1071     xmlstream << "<asia/>";
1072     xmlstream << "<africa/>";
1073     xmlstream << "<europe/>";
1074     xmlstream << "<america/>";
1075     xmlstream << "<australia/>";
1076     xmlstream << "<antartic/>";
1077     xmlstream << "</continents>";
1078     xmlstream << "<oceans>";
1079     xmlstream << "<pacific/>";
1080     xmlstream << "<atlantic/>";
1081     xmlstream << "</oceans>";
1082     xmlstream << "</earth>";
1083     xmldevice.close();
1084 
1085     KoXmlDocument doc(false);
1086     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
1087     QCOMPARE(errorMsg.isEmpty(), true);
1088     QCOMPARE(errorLine, 0);
1089     QCOMPARE(errorColumn, 0);
1090 
1091     KoXmlElement earthElement;
1092     earthElement = doc.documentElement().toElement();
1093     QCOMPARE(earthElement.isNull(), false);
1094     QCOMPARE(earthElement.isElement(), true);
1095     QCOMPARE(earthElement.parentNode().isNull(), false);
1096     QCOMPARE(earthElement.hasChildNodes(), true);
1097     QCOMPARE(KoXml::childNodesCount(earthElement), 2);
1098     QCOMPARE(earthElement.tagName(), QString("earth"));
1099     QCOMPARE(earthElement.prefix().isNull(), true);
1100 
1101     // this ensures that all child nodes of <earth> are loaded
1102     earthElement.firstChild();
1103 
1104     // explicitly unload all child nodes of <earth>
1105     KoXml::unload(earthElement);
1106 
1107     // we should get the correct first child
1108     KoXmlElement continentsElement = earthElement.firstChild().toElement();
1109     QCOMPARE(continentsElement.nodeName(), QString("continents"));
1110     QCOMPARE(continentsElement.isNull(), false);
1111     QCOMPARE(continentsElement.isElement(), true);
1112     QCOMPARE(continentsElement.isText(), false);
1113     QCOMPARE(continentsElement.isDocument(), false);
1114     QCOMPARE(continentsElement.hasChildNodes(), true);
1115     QCOMPARE(KoXml::childNodesCount(continentsElement), 6);
1116 
1117     // let us unload everything again
1118     KoXml::unload(earthElement);
1119 
1120     // we should get the correct last child
1121     KoXmlElement oceansElement = earthElement.lastChild().toElement();
1122     QCOMPARE(oceansElement.nodeName(), QString("oceans"));
1123     QCOMPARE(oceansElement.isNull(), false);
1124     QCOMPARE(oceansElement.isElement(), true);
1125     QCOMPARE(oceansElement.isText(), false);
1126     QCOMPARE(oceansElement.isDocument(), false);
1127     QCOMPARE(oceansElement.hasChildNodes(), true);
1128     QCOMPARE(KoXml::childNodesCount(continentsElement), 6);
1129 }
1130 
testSimpleXML()1131 void TestXmlReaderWithoutSpaces::testSimpleXML()
1132 {
1133     QString errorMsg;
1134     int errorLine = 0;
1135     int errorColumn = 0;
1136 
1137     QBuffer xmldevice;
1138     xmldevice.open(QIODevice::WriteOnly);
1139     QTextStream xmlstream(&xmldevice);
1140     xmlstream << "<solarsystem>";
1141     xmlstream   << "<mercurius/>";
1142     xmlstream   << "<venus/>";
1143     xmlstream   << "<earth>";
1144     xmlstream     << "<moon/>";
1145     xmlstream   << "</earth>";
1146     xmlstream   << "<mars/>";
1147     xmlstream   << "<jupiter/>";
1148     xmlstream << "</solarsystem>";
1149     xmldevice.close();
1150 
1151     KoXmlDocument doc(false);
1152     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
1153     QCOMPARE(errorMsg.isEmpty(), true);
1154     QCOMPARE(errorLine, 0);
1155     QCOMPARE(errorColumn, 0);
1156 
1157     // <solarsystem>
1158     KoXmlElement rootElement;
1159     rootElement = doc.documentElement();
1160     QCOMPARE(rootElement.isNull(), false);
1161     QCOMPARE(rootElement.isElement(), true);
1162     QCOMPARE(rootElement.parentNode().isNull(), false);
1163     QCOMPARE(rootElement.hasChildNodes(), true);
1164     QCOMPARE(KoXml::childNodesCount(rootElement), 5);
1165     QCOMPARE(rootElement.tagName(), QString("solarsystem"));
1166     QCOMPARE(rootElement.prefix().isNull(), true);
1167 
1168     // node <mercurius>
1169     KoXmlNode firstPlanetNode;
1170     firstPlanetNode = rootElement.firstChild();
1171     QCOMPARE(firstPlanetNode.isNull(), false);
1172     QCOMPARE(firstPlanetNode.isElement(), true);
1173     QCOMPARE(firstPlanetNode.nextSibling().isNull(), false);
1174     QCOMPARE(firstPlanetNode.previousSibling().isNull(), true);
1175     QCOMPARE(firstPlanetNode.parentNode().isNull(), false);
1176     QCOMPARE(firstPlanetNode.parentNode() == rootElement, true);
1177     QCOMPARE(firstPlanetNode.parentNode() != rootElement, false);
1178     QCOMPARE(firstPlanetNode.hasChildNodes(), false);
1179     QCOMPARE(KoXml::childNodesCount(firstPlanetNode), 0);
1180     QCOMPARE(firstPlanetNode.firstChild().isNull(), true);
1181     QCOMPARE(firstPlanetNode.lastChild().isNull(), true);
1182 
1183     // element <mercurius>
1184     KoXmlElement firstPlanetElement;
1185     firstPlanetElement = firstPlanetNode.toElement();
1186     QCOMPARE(firstPlanetElement.isNull(), false);
1187     QCOMPARE(firstPlanetElement.isElement(), true);
1188     QCOMPARE(firstPlanetElement.parentNode().isNull(), false);
1189     QCOMPARE(firstPlanetElement.parentNode() == rootElement, true);
1190     QCOMPARE(firstPlanetElement.hasChildNodes(), false);
1191     QCOMPARE(KoXml::childNodesCount(firstPlanetNode), 0);
1192     QCOMPARE(firstPlanetElement.firstChild().isNull(), true);
1193     QCOMPARE(firstPlanetElement.lastChild().isNull(), true);
1194     QCOMPARE(firstPlanetElement.tagName(), QString("mercurius"));
1195     QCOMPARE(firstPlanetElement.prefix().isNull(), true);
1196 
1197     // node <venus>
1198     KoXmlNode secondPlanetNode;
1199     secondPlanetNode = firstPlanetNode.nextSibling();
1200     QCOMPARE(secondPlanetNode.isNull(), false);
1201     QCOMPARE(secondPlanetNode.isElement(), true);
1202     QCOMPARE(secondPlanetNode.nextSibling().isNull(), false);
1203     QCOMPARE(secondPlanetNode.previousSibling().isNull(), false);
1204     QCOMPARE(secondPlanetNode.previousSibling() == firstPlanetNode, true);
1205     QCOMPARE(secondPlanetNode.previousSibling() == firstPlanetElement, true);
1206     QCOMPARE(secondPlanetNode.parentNode().isNull(), false);
1207     QCOMPARE(secondPlanetNode.parentNode() == rootElement, true);
1208     QCOMPARE(secondPlanetNode.parentNode() != rootElement, false);
1209     QCOMPARE(secondPlanetNode.hasChildNodes(), false);
1210     QCOMPARE(KoXml::childNodesCount(secondPlanetNode), 0);
1211     QCOMPARE(secondPlanetNode.firstChild().isNull(), true);
1212     QCOMPARE(secondPlanetNode.lastChild().isNull(), true);
1213 
1214     // element <venus>
1215     KoXmlElement secondPlanetElement;
1216     secondPlanetElement = secondPlanetNode.toElement();
1217     QCOMPARE(secondPlanetElement.isNull(), false);
1218     QCOMPARE(secondPlanetElement.isElement(), true);
1219     QCOMPARE(secondPlanetElement.nextSibling().isNull(), false);
1220     QCOMPARE(secondPlanetElement.previousSibling().isNull(), false);
1221     QCOMPARE(secondPlanetElement.previousSibling() == firstPlanetNode, true);
1222     QCOMPARE(secondPlanetElement.previousSibling() == firstPlanetElement, true);
1223     QCOMPARE(secondPlanetElement.parentNode().isNull(), false);
1224     QCOMPARE(secondPlanetElement.parentNode() == rootElement, true);
1225     QCOMPARE(secondPlanetElement.parentNode() != rootElement, false);
1226     QCOMPARE(secondPlanetElement.hasChildNodes(), false);
1227     QCOMPARE(KoXml::childNodesCount(secondPlanetNode), 0);
1228     QCOMPARE(secondPlanetElement.firstChild().isNull(), true);
1229     QCOMPARE(secondPlanetElement.lastChild().isNull(), true);
1230     QCOMPARE(secondPlanetElement.tagName(), QString("venus"));
1231     QCOMPARE(secondPlanetElement.prefix().isNull(), true);
1232 }
1233 
testRootError()1234 void TestXmlReaderWithoutSpaces::testRootError()
1235 {
1236     QString errorMsg;
1237     int errorLine = 0;
1238     int errorColumn = 0;
1239 
1240     // multiple root nodes are not valid !
1241     QBuffer xmldevice;
1242     xmldevice.open(QIODevice::WriteOnly);
1243     QTextStream xmlstream(&xmldevice);
1244     xmlstream << "<earth></earth><moon></moon>";
1245     xmldevice.close();
1246 
1247     KoXmlDocument doc(false);
1248     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), false);
1249     QCOMPARE(errorMsg.isEmpty(), false);
1250     QCOMPARE(errorMsg, QCoreApplication::translate("QXmlStream", "Extra content at end of document."));
1251     QCOMPARE(errorLine, 1);
1252     QCOMPARE(errorColumn, 21);
1253 }
1254 
testMismatchedTag()1255 void TestXmlReaderWithoutSpaces::testMismatchedTag()
1256 {
1257     QString errorMsg;
1258     int errorLine = 0;
1259     int errorColumn = 0;
1260 
1261     QBuffer xmldevice;
1262     xmldevice.open(QIODevice::WriteOnly);
1263     QTextStream xmlstream(&xmldevice);
1264     xmlstream << "<earth></e>";
1265     xmldevice.close();
1266 
1267     KoXmlDocument doc(false);
1268     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), false);
1269     QCOMPARE(errorMsg.isEmpty(), false);
1270     QCOMPARE(errorMsg, QCoreApplication::translate("QXmlStream", "Opening and ending tag mismatch."));
1271     QCOMPARE(errorLine, 1);
1272     QCOMPARE(errorColumn, 11);
1273 }
1274 
dumpNodes(const KoXmlNode & node,int level=0)1275 static void dumpNodes(const KoXmlNode &node, int level=0)
1276 {
1277     QString indent = QString("%1").arg("", level*3);
1278     if (node.isNull()) {
1279         qDebug()<<indent<<"null";
1280     }
1281     qDebug()<<indent<<node.nodeName();
1282     for(KoXmlNode n = node.firstChild(); ! n.isNull(); n = n.nextSibling() ) {
1283         dumpNodes(n, level+1);
1284     }
1285 
1286 }
dumpNodes(const QDomNode & node,int level=0)1287 static void dumpNodes(const QDomNode &node, int level=0)
1288 {
1289     QString indent = QString("%1").arg("", level*3);
1290     if (node.isNull()) {
1291         qDebug()<<indent<<"null";
1292     }
1293     qDebug()<<indent<<node.nodeName();
1294     for(QDomNode n = node.firstChild(); ! n.isNull(); n = n.nextSibling() ) {
1295         dumpNodes(n, level+1);
1296     }
1297 
1298 }
testConvertQDomDocument()1299 void TestXmlReaderWithoutSpaces::testConvertQDomDocument()
1300 {
1301     QString errorMsg;
1302     int errorLine = 0;
1303     int errorColumn = 0;
1304 
1305     QBuffer xmldevice;
1306     xmldevice.open(QIODevice::WriteOnly);
1307     QTextStream xmlstream(&xmldevice);
1308     xmlstream << "<solarsystem star=\"sun\">";
1309     xmlstream   << "<mercurius/>";
1310     xmlstream   << "<venus/>";
1311     xmlstream   << "<earth habitable=\"true\"><p>The best place</p>";
1312     xmlstream     << "<moon  habitable=\"possible\"/>";
1313     xmlstream   << "</earth>";
1314     xmlstream   << "<mars/>";
1315     xmlstream   << "<jupiter/>";
1316     xmlstream << "</solarsystem>";
1317     xmldevice.close();
1318 
1319     KoXmlDocument doc(false);
1320     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
1321     QCOMPARE(errorMsg.isEmpty(), true);
1322     QCOMPARE(errorLine, 0);
1323     QCOMPARE(errorColumn, 0);
1324 
1325     dumpNodes(doc);
1326     // <solarsystem>
1327     KoXmlElement rootElement;
1328     rootElement = doc.documentElement();
1329     QCOMPARE(rootElement.isNull(), false);
1330     QCOMPARE(rootElement.isElement(), true);
1331     QCOMPARE(rootElement.parentNode().isNull(), false);
1332     QCOMPARE(rootElement.hasChildNodes(), true);
1333     QCOMPARE(KoXml::childNodesCount(rootElement), 5);
1334     QCOMPARE(rootElement.tagName(), QString("solarsystem"));
1335     QCOMPARE(rootElement.prefix().isNull(), true);
1336 
1337     // now test converting KoXmlDocument to QDomDocument
1338     QDomDocument universeDoc = KoXml::asQDomDocument(doc);
1339 
1340     // <solarsystem>
1341     QDomElement solarSystemElement = universeDoc.documentElement();
1342     QCOMPARE(solarSystemElement.isNull(), false);
1343     QCOMPARE(solarSystemElement.isElement(), true);
1344     QCOMPARE(solarSystemElement.parentNode().isNull(), false);
1345     QCOMPARE(solarSystemElement.hasChildNodes(), true);
1346     QCOMPARE(solarSystemElement.tagName(), QString("solarsystem"));
1347     QCOMPARE(solarSystemElement.prefix().isNull(), true);
1348 
1349     // <earth>
1350     QDomElement earthElement = solarSystemElement.namedItem("earth").toElement();
1351     QCOMPARE(earthElement.isNull(), false);
1352     QCOMPARE(earthElement.isElement(), true);
1353     QCOMPARE(earthElement.parentNode().isNull(), false);
1354     QCOMPARE(earthElement.hasAttribute("habitable"), true);
1355     QCOMPARE(earthElement.hasChildNodes(), true);
1356     QCOMPARE(earthElement.tagName(), QString("earth"));
1357     QCOMPARE(earthElement.prefix().isNull(), true);
1358 
1359     // <p> in <earth>
1360     QDomNode placeNode = earthElement.firstChild();
1361     qDebug()<<"placeNode"<<placeNode.nodeName();
1362     dumpNodes(placeNode);
1363     QCOMPARE(placeNode.isNull(), false);
1364     QCOMPARE(placeNode.isElement(), true);
1365     QCOMPARE(placeNode.toElement().text(), QString("The best place"));
1366     QCOMPARE(placeNode.nextSibling().isNull(), false);
1367     QCOMPARE(placeNode.previousSibling().isNull(), true);
1368     QCOMPARE(placeNode.parentNode().isNull(), false);
1369     QCOMPARE(placeNode.parentNode() == earthElement, true);
1370     QCOMPARE(placeNode.hasChildNodes(), true);
1371     QCOMPARE(placeNode.childNodes().count(), 1);
1372 
1373     //printf("Result:\n%s\n\n", qPrintable(universeDoc.toString()));
1374 }
1375 
testConvertQDomElement()1376 void TestXmlReaderWithoutSpaces::testConvertQDomElement()
1377 {
1378     QString errorMsg;
1379     int errorLine = 0;
1380     int errorColumn = 0;
1381 
1382     QBuffer xmldevice;
1383     xmldevice.open(QIODevice::WriteOnly);
1384     QTextStream xmlstream(&xmldevice);
1385     xmlstream << "<universe>";
1386     xmlstream  <<  "<solarsystem star=\"sun\">";
1387     xmlstream   << "<mercurius/>";
1388     xmlstream   << "<venus/>";
1389     xmlstream   << "<earth habitable=\"true\"><p>The best place</p>";
1390     xmlstream     << "<moon  habitable=\"possible\"/>";
1391     xmlstream   << "</earth>";
1392     xmlstream   << "<mars/>";
1393     xmlstream   << "<jupiter/>";
1394     xmlstream  <<  "</solarsystem>";
1395     xmlstream << "</universe>";
1396     xmldevice.close();
1397 
1398     KoXmlDocument doc(false);
1399     QCOMPARE(doc.setContent(&xmldevice, &errorMsg, &errorLine, &errorColumn), true);
1400     QCOMPARE(errorMsg.isEmpty(), true);
1401     QCOMPARE(errorLine, 0);
1402     QCOMPARE(errorColumn, 0);
1403 
1404     // <solarsystem>
1405     KoXmlElement rootElement;
1406     rootElement = doc.documentElement();
1407     QCOMPARE(rootElement.isNull(), false);
1408     QCOMPARE(rootElement.isElement(), true);
1409     QCOMPARE(rootElement.parentNode().isNull(), false);
1410     QCOMPARE(rootElement.hasChildNodes(), true);
1411     QCOMPARE(KoXml::childNodesCount(rootElement), 1);
1412     QCOMPARE(rootElement.tagName(), QString("universe"));
1413     QCOMPARE(rootElement.prefix().isNull(), true);
1414 
1415     // now test converting KoXmlElement to QDomElement
1416     QDomDocument solarDoc;
1417     KoXml::asQDomElement(solarDoc, rootElement.firstChild().toElement());
1418 
1419     // <solarsystem>
1420     QDomElement solarSystemElement = solarDoc.documentElement();
1421     QCOMPARE(solarSystemElement.isNull(), false);
1422     QCOMPARE(solarSystemElement.isElement(), true);
1423     QCOMPARE(solarSystemElement.parentNode().isNull(), false);
1424     QCOMPARE(solarSystemElement.hasChildNodes(), true);
1425     QCOMPARE(solarSystemElement.tagName(), QString("solarsystem"));
1426     QCOMPARE(solarSystemElement.prefix().isNull(), true);
1427 
1428     // <earth>
1429     QDomElement earthElement = solarSystemElement.namedItem("earth").toElement();
1430     QCOMPARE(earthElement.isNull(), false);
1431     QCOMPARE(earthElement.isElement(), true);
1432     QCOMPARE(earthElement.parentNode().isNull(), false);
1433     QCOMPARE(earthElement.hasAttribute("habitable"), true);
1434     QCOMPARE(earthElement.hasChildNodes(), true);
1435     QCOMPARE(earthElement.tagName(), QString("earth"));
1436     QCOMPARE(earthElement.prefix().isNull(), true);
1437 
1438     // <p> in <earth>
1439     QDomNode placeNode = earthElement.firstChild();
1440     QCOMPARE(placeNode.isNull(), false);
1441     QCOMPARE(placeNode.isElement(), true);
1442     QCOMPARE(placeNode.toElement().text(), QString("The best place"));
1443     QCOMPARE(placeNode.nextSibling().isNull(), false);
1444     QCOMPARE(placeNode.previousSibling().isNull(), true);
1445     QCOMPARE(placeNode.parentNode().isNull(), false);
1446     QCOMPARE(placeNode.parentNode() == earthElement, true);
1447     QCOMPARE(placeNode.hasChildNodes(), true);
1448     QCOMPARE(placeNode.childNodes().count(), 1);
1449 
1450     //printf("Result:\n%s\n\n", qPrintable(universeDoc.toString()));
1451 }
1452 
1453 
testSimpleOpenDocumentText()1454 void TestXmlReaderWithoutSpaces::testSimpleOpenDocumentText()
1455 {
1456     QString errorMsg;
1457     int errorLine = 0;
1458     int errorColumn = 0;
1459 
1460     QBuffer xmldevice;
1461     xmldevice.open(QIODevice::WriteOnly);
1462     QTextStream xmlstream(&xmldevice);
1463 
1464     // content.xml from a simple OpenDocument text
1465     // it has only paragraph "Hello, world!"
1466     // automatic styles, declarations and unnecessary namespaces are omitted.
1467     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1468     xmlstream << "<office:document-content ";
1469     xmlstream << " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"";
1470     xmlstream << " xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"";
1471     xmlstream << " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" ";
1472     xmlstream << "   office:version=\"1.0\">";
1473     xmlstream  << "<office:automatic-styles/>";
1474     xmlstream  << "<office:body>";
1475     xmlstream   << "<office:text>";
1476     xmlstream    << "<text:p text:style-name=\"Standard\">Hello, world!</text:p>";
1477     xmlstream   << "</office:text>";
1478     xmlstream  << "</office:body>";
1479     xmlstream << "</office:document-content>";
1480     xmldevice.close();
1481 
1482     KoXmlDocument doc(false);
1483     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
1484     QCOMPARE(errorMsg.isEmpty(), true);
1485     QCOMPARE(errorLine, 0);
1486     QCOMPARE(errorColumn, 0);
1487 
1488     const char* officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
1489     const char* textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
1490 
1491     // <office:document-content>
1492     KoXmlElement contentElement;
1493     contentElement = doc.documentElement();
1494     QCOMPARE(contentElement.isNull(), false);
1495     QCOMPARE(contentElement.isElement(), true);
1496     QCOMPARE(contentElement.parentNode().isNull(), false);
1497     QCOMPARE(contentElement.parentNode().toDocument() == doc, true);
1498     QCOMPARE(KoXml::childNodesCount(contentElement), 2);
1499     QCOMPARE(contentElement.firstChild().isNull(), false);
1500     QCOMPARE(contentElement.lastChild().isNull(), false);
1501     QCOMPARE(contentElement.previousSibling().isNull(), false);
1502     QCOMPARE(contentElement.nextSibling().isNull(), true);
1503     QCOMPARE(contentElement.localName(), QString("document-content"));
1504     QCOMPARE(contentElement.hasAttributeNS(officeNS, "version"), true);
1505     QCOMPARE(contentElement.attributeNS(officeNS, "version", ""), QString("1.0"));
1506 
1507     // <office:automatic-styles>
1508     KoXmlElement stylesElement;
1509     stylesElement = KoXml::namedItemNS(contentElement, officeNS, "automatic-styles");
1510     QCOMPARE(stylesElement.isNull(), false);
1511     QCOMPARE(stylesElement.isElement(), true);
1512     QCOMPARE(stylesElement.parentNode().isNull(), false);
1513     QCOMPARE(stylesElement.parentNode() == contentElement, true);
1514     QCOMPARE(KoXml::childNodesCount(stylesElement), 0);
1515     QCOMPARE(stylesElement.firstChild().isNull(), true);
1516     QCOMPARE(stylesElement.lastChild().isNull(), true);
1517     QCOMPARE(stylesElement.previousSibling().isNull(), true);
1518     QCOMPARE(stylesElement.nextSibling().isNull(), false);
1519     QCOMPARE(stylesElement.localName(), QString("automatic-styles"));
1520 
1521     // also same <office:automatic-styles>, but without namedItemNS
1522     KoXmlNode styles2Element;
1523     styles2Element = contentElement.firstChild().toElement();
1524     QCOMPARE(styles2Element.isNull(), false);
1525     QCOMPARE(styles2Element.isElement(), true);
1526     QCOMPARE(styles2Element.parentNode().isNull(), false);
1527     QCOMPARE(styles2Element.parentNode() == contentElement, true);
1528     QCOMPARE(KoXml::childNodesCount(styles2Element), 0);
1529     QCOMPARE(styles2Element.firstChild().isNull(), true);
1530     QCOMPARE(styles2Element.lastChild().isNull(), true);
1531     QCOMPARE(styles2Element.previousSibling().isNull(), true);
1532     QCOMPARE(styles2Element.nextSibling().isNull(), false);
1533     QCOMPARE(styles2Element.localName(), QString("automatic-styles"));
1534 
1535     // <office:body>
1536     KoXmlElement bodyElement;
1537     bodyElement = KoXml::namedItemNS(contentElement, officeNS, "body");
1538     QCOMPARE(bodyElement.isNull(), false);
1539     QCOMPARE(bodyElement.isElement(), true);
1540     QCOMPARE(bodyElement.parentNode().isNull(), false);
1541     QCOMPARE(bodyElement.parentNode() == contentElement, true);
1542     QCOMPARE(KoXml::childNodesCount(bodyElement), 1);
1543     QCOMPARE(bodyElement.firstChild().isNull(), false);
1544     QCOMPARE(bodyElement.lastChild().isNull(), false);
1545     QCOMPARE(bodyElement.previousSibling().isNull(), false);
1546     QCOMPARE(bodyElement.nextSibling().isNull(), true);
1547     QCOMPARE(bodyElement.localName(), QString("body"));
1548 
1549     // also same <office:body>, but without namedItemNS
1550     KoXmlElement body2Element;
1551     body2Element = stylesElement.nextSibling().toElement();
1552     QCOMPARE(body2Element.isNull(), false);
1553     QCOMPARE(body2Element.isElement(), true);
1554     QCOMPARE(body2Element.parentNode().isNull(), false);
1555     QCOMPARE(body2Element.parentNode() == contentElement, true);
1556     QCOMPARE(KoXml::childNodesCount(body2Element), 1);
1557     QCOMPARE(body2Element.firstChild().isNull(), false);
1558     QCOMPARE(body2Element.lastChild().isNull(), false);
1559     QCOMPARE(body2Element.previousSibling().isNull(), false);
1560     QCOMPARE(body2Element.nextSibling().isNull(), true);
1561     QCOMPARE(body2Element.localName(), QString("body"));
1562 
1563     // <office:text>
1564     KoXmlElement textElement;
1565     textElement = KoXml::namedItemNS(bodyElement, officeNS, "text");
1566     QCOMPARE(textElement.isNull(), false);
1567     QCOMPARE(textElement.isElement(), true);
1568     QCOMPARE(textElement.parentNode().isNull(), false);
1569     QCOMPARE(textElement.parentNode() == bodyElement, true);
1570     QCOMPARE(KoXml::childNodesCount(textElement), 1);
1571     QCOMPARE(textElement.firstChild().isNull(), false);
1572     QCOMPARE(textElement.lastChild().isNull(), false);
1573     QCOMPARE(textElement.previousSibling().isNull(), true);
1574     QCOMPARE(textElement.nextSibling().isNull(), true);
1575     QCOMPARE(textElement.localName(), QString("text"));
1576 
1577     // the same <office:text>, but without namedItemNS
1578     KoXmlElement text2Element;
1579     text2Element = bodyElement.firstChild().toElement();
1580     QCOMPARE(text2Element.isNull(), false);
1581     QCOMPARE(text2Element.isElement(), true);
1582     QCOMPARE(text2Element.parentNode().isNull(), false);
1583     QCOMPARE(text2Element.parentNode() == bodyElement, true);
1584     QCOMPARE(KoXml::childNodesCount(text2Element), 1);
1585     QCOMPARE(text2Element.firstChild().isNull(), false);
1586     QCOMPARE(text2Element.lastChild().isNull(), false);
1587     QCOMPARE(text2Element.previousSibling().isNull(), true);
1588     QCOMPARE(text2Element.nextSibling().isNull(), true);
1589     QCOMPARE(text2Element.localName(), QString("text"));
1590 
1591     // <text:p>
1592     KoXmlElement parElement;
1593     parElement = textElement.firstChild().toElement();
1594     QCOMPARE(parElement.isNull(), false);
1595     QCOMPARE(parElement.isElement(), true);
1596     QCOMPARE(parElement.parentNode().isNull(), false);
1597     QCOMPARE(parElement.parentNode() == textElement, true);
1598     QCOMPARE(KoXml::childNodesCount(parElement), 1);
1599     QCOMPARE(parElement.firstChild().isNull(), false);
1600     QCOMPARE(parElement.lastChild().isNull(), false);
1601     QCOMPARE(parElement.previousSibling().isNull(), true);
1602     QCOMPARE(parElement.nextSibling().isNull(), true);
1603     QCOMPARE(parElement.tagName(), QString("p"));
1604     QCOMPARE(parElement.text(), QString("Hello, world!"));
1605     QCOMPARE(parElement.attributeNS(QString(textNS), "style-name", ""), QString("Standard"));
1606 }
1607 
testWhitespace()1608 void TestXmlReaderWithoutSpaces::testWhitespace()
1609 {
1610     QString errorMsg;
1611     int errorLine = 0;
1612     int errorColumn = 0;
1613 
1614     QBuffer xmldevice;
1615     xmldevice.open(QIODevice::WriteOnly);
1616     QTextStream xmlstream(&xmldevice);
1617 
1618     // content.xml for testing paragraphs with whitespace
1619     /* The list of elements for which whitespace should be preserved can be
1620        obtained from the Relax NG schema with these commands:
1621 
1622         cat OpenDocument-schema-v1.0-os.rng| xmlstarlet sel \
1623          -N s="http://relaxng.org/ns/structure/1.0" -t -m '//s:text' \
1624          -v '../@name' -n |grep :
1625         cat OpenDocument-schema-v1.0-os.rng| xmlstarlet sel \
1626          -N s="http://relaxng.org/ns/structure/1.0" \
1627          -t -m "//s:ref[@name='paragraph-content']" -v '../../@name' -n |grep :
1628     */
1629 
1630     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1631     xmlstream << "<office:document-content ";
1632     xmlstream << " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"";
1633     xmlstream << " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\">";
1634     xmlstream   << "<text:p> </text:p>";
1635     xmlstream   << "<text:p> <text:span/> </text:p>";
1636     xmlstream << "</office:document-content>";
1637     xmldevice.close();
1638 
1639     KoXmlDocument doc(false);
1640     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
1641     QCOMPARE(errorMsg.isEmpty(), true);
1642     QCOMPARE(errorLine, 0);
1643     QCOMPARE(errorColumn, 0);
1644 
1645     KoXmlElement p1;
1646     p1 = doc.documentElement().firstChild().toElement();
1647     QCOMPARE(p1.isNull(), false);
1648     QCOMPARE(p1.isElement(), true);
1649     QCOMPARE(KoXml::childNodesCount(p1), 1);
1650 
1651     KoXmlElement p2;
1652     p2 = p1.nextSibling().toElement();
1653     QCOMPARE(p2.isNull(), false);
1654     QCOMPARE(p2.isElement(), true);
1655     QCOMPARE(KoXml::childNodesCount(p2), 3);
1656 }
1657 
testSimpleOpenDocumentSpreadsheet()1658 void TestXmlReaderWithoutSpaces::testSimpleOpenDocumentSpreadsheet()
1659 {
1660     QString errorMsg;
1661     int errorLine = 0;
1662     int errorColumn = 0;
1663 
1664     QBuffer xmldevice;
1665     xmldevice.open(QIODevice::WriteOnly);
1666     QTextStream xmlstream(&xmldevice);
1667 
1668     // content.xml from a simple OpenDocument spreadsheet
1669     // the document has three worksheets, the last two are empty.
1670     // on the first sheet, cell A1 contains the text "Hello, world".
1671     // automatic styles, font declarations and unnecessary namespaces are omitted.
1672 
1673     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1674     xmlstream << "<office:document-content ";
1675     xmlstream << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" ";
1676     xmlstream << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" ";
1677     xmlstream << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\">";
1678     xmlstream << "<office:body>";
1679     xmlstream << "<office:spreadsheet>";
1680     xmlstream << "<table:table table:name=\"Sheet1\" table:style-name=\"ta1\" table:print=\"false\">";
1681     xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>";
1682     xmlstream << "<table:table-row table:style-name=\"ro1\">";
1683     xmlstream << "<table:table-cell office:value-type=\"string\">";
1684     xmlstream << "<text:p>Hello, world</text:p>";
1685     xmlstream << "</table:table-cell>";
1686     xmlstream << "</table:table-row>";
1687     xmlstream << "</table:table>";
1688     xmlstream << "<table:table table:name=\"Sheet2\" table:style-name=\"ta1\" table:print=\"false\">";
1689     xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>";
1690     xmlstream << "<table:table-row table:style-name=\"ro1\">";
1691     xmlstream << "<table:table-cell/>";
1692     xmlstream << "</table:table-row>";
1693     xmlstream << "</table:table>";
1694     xmlstream << "<table:table table:name=\"Sheet3\" table:style-name=\"ta1\" table:print=\"false\">";
1695     xmlstream << "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/>";
1696     xmlstream << "<table:table-row table:style-name=\"ro1\">";
1697     xmlstream << "<table:table-cell/>";
1698     xmlstream << "</table:table-row>";
1699     xmlstream << "</table:table>";
1700     xmlstream << "</office:spreadsheet>";
1701     xmlstream << "</office:body>";
1702     xmlstream << "</office:document-content>";
1703     xmldevice.close();
1704 
1705     KoXmlDocument doc(false);
1706     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
1707     QCOMPARE(errorMsg.isEmpty(), true);
1708     QCOMPARE(errorLine, 0);
1709     QCOMPARE(errorColumn, 0);
1710 
1711     QString officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
1712     QString tableNS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
1713 
1714     // <office:document-content>
1715     KoXmlElement contentElement;
1716     contentElement = doc.documentElement();
1717     QCOMPARE(contentElement.isNull(), false);
1718     QCOMPARE(contentElement.isElement(), true);
1719     QCOMPARE(contentElement.parentNode().isNull(), false);
1720     QCOMPARE(contentElement.parentNode().toDocument() == doc, true);
1721     QCOMPARE(KoXml::childNodesCount(contentElement), 1);
1722     QCOMPARE(contentElement.firstChild().isNull(), false);
1723     QCOMPARE(contentElement.lastChild().isNull(), false);
1724     QCOMPARE(contentElement.previousSibling().isNull(), false);
1725     QCOMPARE(contentElement.nextSibling().isNull(), true);
1726     QCOMPARE(contentElement.localName(), QString("document-content"));
1727 
1728     // <office:body>
1729     KoXmlElement bodyElement;
1730     bodyElement = contentElement.firstChild().toElement();
1731     QCOMPARE(bodyElement.isNull(), false);
1732     QCOMPARE(bodyElement.isElement(), true);
1733     QCOMPARE(bodyElement.parentNode().isNull(), false);
1734     QCOMPARE(bodyElement.parentNode() == contentElement, true);
1735     QCOMPARE(KoXml::childNodesCount(bodyElement), 1);
1736     QCOMPARE(bodyElement.firstChild().isNull(), false);
1737     QCOMPARE(bodyElement.lastChild().isNull(), false);
1738     QCOMPARE(bodyElement.previousSibling().isNull(), true);
1739     QCOMPARE(bodyElement.nextSibling().isNull(), true);
1740     QCOMPARE(bodyElement.localName(), QString("body"));
1741 
1742     // <office:spreadsheet>
1743     KoXmlElement spreadsheetElement;
1744     spreadsheetElement = bodyElement.firstChild().toElement();
1745     QCOMPARE(spreadsheetElement.isNull(), false);
1746     QCOMPARE(spreadsheetElement.isElement(), true);
1747     QCOMPARE(spreadsheetElement.parentNode().isNull(), false);
1748     QCOMPARE(spreadsheetElement.parentNode() == bodyElement, true);
1749     QCOMPARE(KoXml::childNodesCount(spreadsheetElement), 3);
1750     QCOMPARE(spreadsheetElement.firstChild().isNull(), false);
1751     QCOMPARE(spreadsheetElement.lastChild().isNull(), false);
1752     QCOMPARE(spreadsheetElement.previousSibling().isNull(), true);
1753     QCOMPARE(spreadsheetElement.nextSibling().isNull(), true);
1754     QCOMPARE(spreadsheetElement.localName(), QString("spreadsheet"));
1755 
1756     // <table:table> for Sheet1
1757     KoXmlElement sheet1Element;
1758     sheet1Element = spreadsheetElement.firstChild().toElement();
1759     QCOMPARE(sheet1Element.isNull(), false);
1760     QCOMPARE(sheet1Element.isElement(), true);
1761     QCOMPARE(sheet1Element.parentNode().isNull(), false);
1762     QCOMPARE(sheet1Element.parentNode() == spreadsheetElement, true);
1763     QCOMPARE(KoXml::childNodesCount(sheet1Element), 2);
1764     QCOMPARE(sheet1Element.firstChild().isNull(), false);
1765     QCOMPARE(sheet1Element.lastChild().isNull(), false);
1766     QCOMPARE(sheet1Element.previousSibling().isNull(), true);
1767     QCOMPARE(sheet1Element.nextSibling().isNull(), false);
1768     QCOMPARE(sheet1Element.tagName(), QString("table"));
1769     QCOMPARE(sheet1Element.hasAttributeNS(tableNS, "name"), true);
1770     QCOMPARE(sheet1Element.attributeNS(tableNS, "name", ""), QString("Sheet1"));
1771     QCOMPARE(sheet1Element.attributeNS(tableNS, "style-name", ""), QString("ta1"));
1772     QCOMPARE(sheet1Element.attributeNS(tableNS, "print", ""), QString("false"));
1773 
1774     //  KoXml::load( sheet1Element, 100 );
1775 
1776     // <table:table-column>
1777     KoXmlElement columnElement;
1778     columnElement = sheet1Element.firstChild().toElement();
1779     QCOMPARE(columnElement.isNull(), false);
1780     QCOMPARE(columnElement.isElement(), true);
1781     QCOMPARE(columnElement.parentNode().isNull(), false);
1782     QCOMPARE(columnElement.parentNode() == sheet1Element, true);
1783     QCOMPARE(KoXml::childNodesCount(columnElement), 0);
1784     QCOMPARE(columnElement.firstChild().isNull(), true);
1785     QCOMPARE(columnElement.lastChild().isNull(), true);
1786     QCOMPARE(columnElement.previousSibling().isNull(), true);
1787     QCOMPARE(columnElement.nextSibling().isNull(), false);
1788     QCOMPARE(columnElement.tagName(), QString("table-column"));
1789     QCOMPARE(columnElement.attributeNS(tableNS, "style-name", ""), QString("co1"));
1790     QCOMPARE(columnElement.attributeNS(tableNS, "default-cell-style-name", ""), QString("Default"));
1791 
1792     // <table:table-row>
1793     KoXmlElement rowElement;
1794     rowElement = columnElement.nextSibling().toElement();
1795     QCOMPARE(rowElement.isNull(), false);
1796     QCOMPARE(rowElement.isElement(), true);
1797     QCOMPARE(rowElement.parentNode().isNull(), false);
1798     QCOMPARE(rowElement.parentNode() == sheet1Element, true);
1799     QCOMPARE(KoXml::childNodesCount(rowElement), 1);
1800     QCOMPARE(rowElement.firstChild().isNull(), false);
1801     QCOMPARE(rowElement.lastChild().isNull(), false);
1802     QCOMPARE(rowElement.previousSibling().isNull(), false);
1803     QCOMPARE(rowElement.nextSibling().isNull(), true);
1804     QCOMPARE(rowElement.tagName(), QString("table-row"));
1805     QCOMPARE(rowElement.attributeNS(tableNS, "style-name", ""), QString("ro1"));
1806 
1807     // <table:table-cell>
1808     KoXmlElement cellElement;
1809     cellElement = rowElement.firstChild().toElement();
1810     QCOMPARE(cellElement.isNull(), false);
1811     QCOMPARE(cellElement.isElement(), true);
1812     QCOMPARE(cellElement.parentNode().isNull(), false);
1813     QCOMPARE(cellElement.parentNode() == rowElement, true);
1814     QCOMPARE(KoXml::childNodesCount(cellElement), 1);
1815     QCOMPARE(cellElement.firstChild().isNull(), false);
1816     QCOMPARE(cellElement.lastChild().isNull(), false);
1817     QCOMPARE(cellElement.previousSibling().isNull(), true);
1818     QCOMPARE(cellElement.nextSibling().isNull(), true);
1819     QCOMPARE(cellElement.tagName(), QString("table-cell"));
1820     QCOMPARE(cellElement.attributeNS(officeNS, "value-type", ""), QString("string"));
1821 
1822     // <text:p>
1823     KoXmlElement parElement;
1824     parElement = cellElement.firstChild().toElement();
1825     QCOMPARE(parElement.isNull(), false);
1826     QCOMPARE(parElement.isElement(), true);
1827     QCOMPARE(parElement.parentNode().isNull(), false);
1828     QCOMPARE(parElement.parentNode() == cellElement, true);
1829     QCOMPARE(KoXml::childNodesCount(parElement), 1);
1830     QCOMPARE(parElement.firstChild().isNull(), false);
1831     QCOMPARE(parElement.lastChild().isNull(), false);
1832     QCOMPARE(parElement.previousSibling().isNull(), true);
1833     QCOMPARE(parElement.nextSibling().isNull(), true);
1834     QCOMPARE(parElement.tagName(), QString("p"));
1835     QCOMPARE(parElement.text(), QString("Hello, world"));
1836 
1837     // <table:table> for Sheet2
1838     KoXmlElement sheet2Element;
1839     sheet2Element = sheet1Element.nextSibling().toElement();
1840     QCOMPARE(sheet2Element.isNull(), false);
1841     QCOMPARE(sheet2Element.isElement(), true);
1842     QCOMPARE(sheet2Element.parentNode().isNull(), false);
1843     QCOMPARE(sheet2Element.parentNode() == spreadsheetElement, true);
1844     QCOMPARE(KoXml::childNodesCount(sheet2Element), 2);
1845     QCOMPARE(sheet2Element.firstChild().isNull(), false);
1846     QCOMPARE(sheet2Element.lastChild().isNull(), false);
1847     QCOMPARE(sheet2Element.previousSibling().isNull(), false);
1848     QCOMPARE(sheet2Element.nextSibling().isNull(), false);
1849     QCOMPARE(sheet2Element.tagName(), QString("table"));
1850 
1851     // </table:table> for Sheet3
1852     KoXmlElement sheet3Element;
1853     sheet3Element = sheet2Element.nextSibling().toElement();
1854     QCOMPARE(sheet3Element.isNull(), false);
1855     QCOMPARE(sheet3Element.isElement(), true);
1856     QCOMPARE(sheet3Element.parentNode().isNull(), false);
1857     QCOMPARE(sheet3Element.parentNode() == spreadsheetElement, true);
1858     QCOMPARE(KoXml::childNodesCount(sheet3Element), 2);
1859     QCOMPARE(sheet3Element.firstChild().isNull(), false);
1860     QCOMPARE(sheet3Element.lastChild().isNull(), false);
1861     QCOMPARE(sheet3Element.previousSibling().isNull(), false);
1862     QCOMPARE(sheet3Element.nextSibling().isNull(), true);
1863     QCOMPARE(sheet3Element.tagName(), QString("table"));
1864 }
1865 
testSimpleOpenDocumentPresentation()1866 void TestXmlReaderWithoutSpaces::testSimpleOpenDocumentPresentation()
1867 {
1868     QString errorMsg;
1869     int errorLine = 0;
1870     int errorColumn = 0;
1871 
1872     QBuffer xmldevice;
1873     xmldevice.open(QIODevice::WriteOnly);
1874     QTextStream xmlstream(&xmldevice);
1875 
1876     // content.xml from a simple OpenDocument presentation
1877     // styles, declarations and unnecessary namespaces are omitted
1878     // the first page is "Title" and has two text boxes
1879     // the second page is
1880 
1881     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1882     xmlstream << "<office:document-content ";
1883     xmlstream << "  xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" ";
1884     xmlstream << "  xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" ";
1885     xmlstream << "  xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" ";
1886     xmlstream << "  xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" ";
1887     xmlstream << "  xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" ";
1888     xmlstream << "  office:version=\"1.0\">";
1889     xmlstream  << "<office:scripts/>";
1890     xmlstream  << "<office:automatic-styles/>";
1891     xmlstream  << "<office:body>";
1892     xmlstream   << "<office:presentation>";
1893     xmlstream    << "<draw:page draw:name=\"Title\" draw:style-name=\"dp1\" ";
1894     xmlstream    << "   draw:master-page-name=\"lyt-cool\" ";
1895     xmlstream    << "   presentation:presentation-page-layout-name=\"AL1T0\">";
1896     xmlstream     << "<draw:frame presentation:style-name=\"pr1\" ";
1897     xmlstream     << "  draw:text-style-name=\"P2\" draw:layer=\"layout\" ";
1898     xmlstream     << "  svg:width=\"23.912cm\" svg:height=\"3.508cm\" ";
1899     xmlstream     << "  svg:x=\"2.058cm\" svg:y=\"1.543cm\" ";
1900     xmlstream     << "  presentation:class=\"title\" ";
1901     xmlstream     << "  presentation:user-transformed=\"true\">";
1902     xmlstream      << "<draw:text-box>";
1903     xmlstream       << "<text:p text:style-name=\"P1\">Foobar</text:p>";
1904     xmlstream      << "</draw:text-box>";
1905     xmlstream     << "</draw:frame>";
1906     xmlstream     << "<draw:frame presentation:style-name=\"pr2\" ";
1907     xmlstream     << "  draw:text-style-name=\"P3\" draw:layer=\"layout\"";
1908     xmlstream     << "  svg:width=\"23.912cm\" svg:height=\"13.231cm\"";
1909     xmlstream     << "  svg:x=\"2.058cm\" svg:y=\"5.838cm\" ";
1910     xmlstream     << "  presentation:class=\"subtitle\">";
1911     xmlstream      << "<draw:text-box>";
1912     xmlstream       << "<text:p text:style-name=\"P3\">Foo</text:p>";
1913     xmlstream      << "</draw:text-box>";
1914     xmlstream     << "</draw:frame>";
1915     xmlstream     << "<presentation:notes draw:style-name=\"dp2\">";
1916     xmlstream      << "<draw:page-thumbnail draw:style-name=\"gr1\" draw:layer=\"layout\" svg:width=\"13.706cm\" svg:height=\"10.28cm\" svg:x=\"3.647cm\" svg:y=\"2.853cm\" draw:page-number=\"1\" presentation:class=\"page\"/>";
1917     xmlstream      << "<draw:frame presentation:style-name=\"pr3\" draw:text-style-name=\"P1\" draw:layer=\"layout\" svg:width=\"14.518cm\" svg:height=\"11.411cm\" svg:x=\"3.249cm\" svg:y=\"14.13cm\" presentation:class=\"notes\" presentation:placeholder=\"true\">";
1918     xmlstream       << "<draw:text-box/>";
1919     xmlstream      << "</draw:frame>";
1920     xmlstream     << "</presentation:notes>";
1921     xmlstream    << "</draw:page>";
1922     xmlstream    << "<presentation:settings presentation:stay-on-top=\"true\"/>";
1923     xmlstream   << "</office:presentation>";
1924     xmlstream  << "</office:body>";
1925     xmlstream << "</office:document-content>";
1926     xmldevice.close();
1927 
1928     KoXmlDocument doc(false);
1929     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
1930     QCOMPARE(errorMsg.isEmpty(), true);
1931     QCOMPARE(errorLine, 0);
1932     QCOMPARE(errorColumn, 0);
1933 
1934     const char* officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
1935     const char* drawNS = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
1936     const char* textNS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
1937     const char* presentationNS = "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0";
1938     const char* svgNS = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";
1939 
1940     // <office:document-content>
1941     KoXmlElement contentElement;
1942     contentElement = doc.documentElement();
1943     QCOMPARE(contentElement.isNull(), false);
1944 
1945     QCOMPARE(contentElement.isElement(), true);
1946     QCOMPARE(contentElement.parentNode().isNull(), false);
1947     QCOMPARE(contentElement.parentNode().toDocument() == doc, true);
1948     QCOMPARE(KoXml::childNodesCount(contentElement), 3);
1949     QCOMPARE(contentElement.firstChild().isNull(), false);
1950     QCOMPARE(contentElement.lastChild().isNull(), false);
1951     QCOMPARE(contentElement.previousSibling().isNull(), false);
1952     QCOMPARE(contentElement.nextSibling().isNull(), true);
1953     QCOMPARE(contentElement.localName(), QString("document-content"));
1954     QCOMPARE(contentElement.hasAttributeNS(officeNS, "version"), true);
1955     QCOMPARE(contentElement.attributeNS(officeNS, "version", ""), QString("1.0"));
1956 
1957     // <office:scripts>
1958     KoXmlElement scriptsElement;
1959     scriptsElement = KoXml::namedItemNS(contentElement, officeNS, "scripts");
1960     QCOMPARE(scriptsElement.isNull(), false);
1961     QCOMPARE(scriptsElement.isElement(), true);
1962     QCOMPARE(scriptsElement.parentNode().isNull(), false);
1963     QCOMPARE(scriptsElement.parentNode() == contentElement, true);
1964     QCOMPARE(KoXml::childNodesCount(scriptsElement), 0);
1965     QCOMPARE(scriptsElement.firstChild().isNull(), true);
1966     QCOMPARE(scriptsElement.lastChild().isNull(), true);
1967     QCOMPARE(scriptsElement.previousSibling().isNull(), true);
1968     QCOMPARE(scriptsElement.nextSibling().isNull(), false);
1969     QCOMPARE(scriptsElement.localName(), QString("scripts"));
1970 
1971     // <office:automatic-styles>
1972     KoXmlElement stylesElement;
1973     stylesElement = KoXml::namedItemNS(contentElement, officeNS, "automatic-styles");
1974     QCOMPARE(stylesElement.isNull(), false);
1975     QCOMPARE(stylesElement.isElement(), true);
1976     QCOMPARE(stylesElement.parentNode().isNull(), false);
1977     QCOMPARE(stylesElement.parentNode() == contentElement, true);
1978     QCOMPARE(KoXml::childNodesCount(stylesElement), 0);
1979     QCOMPARE(stylesElement.firstChild().isNull(), true);
1980     QCOMPARE(stylesElement.lastChild().isNull(), true);
1981     QCOMPARE(stylesElement.previousSibling().isNull(), false);
1982     QCOMPARE(stylesElement.nextSibling().isNull(), false);
1983     QCOMPARE(stylesElement.localName(), QString("automatic-styles"));
1984 
1985     // also same <office:automatic-styles>, but without namedItemNS
1986     KoXmlNode styles2Element;
1987     styles2Element = scriptsElement.nextSibling().toElement();
1988     QCOMPARE(styles2Element.isNull(), false);
1989     QCOMPARE(styles2Element.isElement(), true);
1990     QCOMPARE(styles2Element.parentNode().isNull(), false);
1991     QCOMPARE(styles2Element.parentNode() == contentElement, true);
1992     QCOMPARE(KoXml::childNodesCount(styles2Element), 0);
1993     QCOMPARE(styles2Element.firstChild().isNull(), true);
1994     QCOMPARE(styles2Element.lastChild().isNull(), true);
1995     QCOMPARE(styles2Element.previousSibling().isNull(), false);
1996     QCOMPARE(styles2Element.nextSibling().isNull(), false);
1997     QCOMPARE(styles2Element.localName(), QString("automatic-styles"));
1998 
1999     // <office:body>
2000     KoXmlElement bodyElement;
2001     bodyElement = KoXml::namedItemNS(contentElement, officeNS, "body");
2002     QCOMPARE(bodyElement.isNull(), false);
2003     QCOMPARE(bodyElement.isElement(), true);
2004     QCOMPARE(bodyElement.parentNode().isNull(), false);
2005     QCOMPARE(bodyElement.parentNode() == contentElement, true);
2006     QCOMPARE(KoXml::childNodesCount(bodyElement), 1);
2007     QCOMPARE(bodyElement.firstChild().isNull(), false);
2008     QCOMPARE(bodyElement.lastChild().isNull(), false);
2009     QCOMPARE(bodyElement.previousSibling().isNull(), false);
2010     QCOMPARE(bodyElement.nextSibling().isNull(), true);
2011     QCOMPARE(bodyElement.localName(), QString("body"));
2012 
2013     // also same <office:body>, but without namedItemNS
2014     KoXmlElement body2Element;
2015     body2Element = stylesElement.nextSibling().toElement();
2016     QCOMPARE(body2Element.isNull(), false);
2017     QCOMPARE(body2Element.isElement(), true);
2018     QCOMPARE(body2Element.parentNode().isNull(), false);
2019     QCOMPARE(body2Element.parentNode() == contentElement, true);
2020     QCOMPARE(KoXml::childNodesCount(body2Element), 1);
2021     QCOMPARE(body2Element.firstChild().isNull(), false);
2022     QCOMPARE(body2Element.lastChild().isNull(), false);
2023     QCOMPARE(body2Element.previousSibling().isNull(), false);
2024     QCOMPARE(body2Element.nextSibling().isNull(), true);
2025     QCOMPARE(body2Element.localName(), QString("body"));
2026 
2027     // <office:presentation>
2028     KoXmlElement presentationElement;
2029     presentationElement = KoXml::namedItemNS(bodyElement, officeNS, "presentation");
2030     QCOMPARE(presentationElement.isNull(), false);
2031     QCOMPARE(presentationElement.isElement(), true);
2032     QCOMPARE(presentationElement.parentNode().isNull(), false);
2033     QCOMPARE(presentationElement.parentNode() == bodyElement, true);
2034     QCOMPARE(KoXml::childNodesCount(presentationElement), 2);
2035     QCOMPARE(presentationElement.firstChild().isNull(), false);
2036     QCOMPARE(presentationElement.lastChild().isNull(), false);
2037     QCOMPARE(presentationElement.previousSibling().isNull(), true);
2038     QCOMPARE(presentationElement.nextSibling().isNull(), true);
2039     QCOMPARE(presentationElement.localName(), QString("presentation"));
2040 
2041     // the same <office:presentation>, but without namedItemNS
2042     KoXmlElement presentation2Element;
2043     presentation2Element = bodyElement.firstChild().toElement();
2044     QCOMPARE(presentation2Element.isNull(), false);
2045     QCOMPARE(presentation2Element.isElement(), true);
2046     QCOMPARE(presentation2Element.parentNode().isNull(), false);
2047     QCOMPARE(presentation2Element.parentNode() == bodyElement, true);
2048     QCOMPARE(KoXml::childNodesCount(presentation2Element), 2);
2049     QCOMPARE(presentation2Element.firstChild().isNull(), false);
2050     QCOMPARE(presentation2Element.lastChild().isNull(), false);
2051     QCOMPARE(presentation2Element.previousSibling().isNull(), true);
2052     QCOMPARE(presentation2Element.nextSibling().isNull(), true);
2053     QCOMPARE(presentation2Element.localName(), QString("presentation"));
2054 
2055     // <draw:page> for "Title"
2056     KoXmlElement titlePageElement;
2057     titlePageElement = presentationElement.firstChild().toElement();
2058     QCOMPARE(titlePageElement.isNull(), false);
2059     QCOMPARE(titlePageElement.isElement(), true);
2060     QCOMPARE(titlePageElement.parentNode().isNull(), false);
2061     QCOMPARE(titlePageElement.parentNode() == presentationElement, true);
2062     QCOMPARE(KoXml::childNodesCount(titlePageElement), 3);
2063     QCOMPARE(titlePageElement.firstChild().isNull(), false);
2064     QCOMPARE(titlePageElement.lastChild().isNull(), false);
2065     QCOMPARE(titlePageElement.previousSibling().isNull(), true);
2066     QCOMPARE(titlePageElement.nextSibling().isNull(), false);
2067     QCOMPARE(titlePageElement.localName(), QString("page"));
2068     QCOMPARE(titlePageElement.attributeNS(drawNS, "name", ""), QString("Title"));
2069     QCOMPARE(titlePageElement.attributeNS(drawNS, "style-name", ""), QString("dp1"));
2070     QCOMPARE(titlePageElement.attributeNS(drawNS, "master-page-name", ""), QString("lyt-cool"));
2071     QCOMPARE(titlePageElement.attributeNS(presentationNS,
2072                                        "presentation-page-layout-name", ""), QString("AL1T0"));
2073 
2074     // <draw:frame> for the title frame
2075     KoXmlElement titleFrameElement;
2076     titleFrameElement = titlePageElement.firstChild().toElement();
2077     QCOMPARE(titleFrameElement.isNull(), false);
2078     QCOMPARE(titleFrameElement.isElement(), true);
2079     QCOMPARE(titleFrameElement.parentNode().isNull(), false);
2080     QCOMPARE(titleFrameElement.parentNode() == titlePageElement, true);
2081     QCOMPARE(KoXml::childNodesCount(titleFrameElement), 1);
2082     QCOMPARE(titleFrameElement.firstChild().isNull(), false);
2083     QCOMPARE(titleFrameElement.lastChild().isNull(), false);
2084     QCOMPARE(titleFrameElement.previousSibling().isNull(), true);
2085     QCOMPARE(titleFrameElement.nextSibling().isNull(), false);
2086     QCOMPARE(titleFrameElement.localName(), QString("frame"));
2087     QCOMPARE(titleFrameElement.attributeNS(presentationNS, "style-name", ""), QString("pr1"));
2088     QCOMPARE(titleFrameElement.attributeNS(presentationNS, "class", ""), QString("title"));
2089     QCOMPARE(titleFrameElement.attributeNS(presentationNS, "user-transformed", ""), QString("true"));
2090     QCOMPARE(titleFrameElement.attributeNS(drawNS, "text-style-name", ""), QString("P2"));
2091     QCOMPARE(titleFrameElement.attributeNS(drawNS, "layer", ""), QString("layout"));
2092     QCOMPARE(titleFrameElement.attributeNS(svgNS, "width", ""), QString("23.912cm"));
2093     QCOMPARE(titleFrameElement.attributeNS(svgNS, "height", ""), QString("3.508cm"));
2094     QCOMPARE(titleFrameElement.attributeNS(svgNS, "x", ""), QString("2.058cm"));
2095     QCOMPARE(titleFrameElement.attributeNS(svgNS, "y", ""), QString("1.543cm"));
2096 
2097     // <draw:text-box> of the title frame
2098     KoXmlElement titleBoxElement;
2099     titleBoxElement = titleFrameElement.firstChild().toElement();
2100     QCOMPARE(titleBoxElement.isNull(), false);
2101     QCOMPARE(titleBoxElement.isElement(), true);
2102     QCOMPARE(titleBoxElement.parentNode().isNull(), false);
2103     QCOMPARE(titleBoxElement.parentNode() == titleFrameElement, true);
2104     QCOMPARE(KoXml::childNodesCount(titleBoxElement), 1);
2105     QCOMPARE(titleBoxElement.firstChild().isNull(), false);
2106     QCOMPARE(titleBoxElement.lastChild().isNull(), false);
2107     QCOMPARE(titleBoxElement.previousSibling().isNull(), true);
2108     QCOMPARE(titleBoxElement.nextSibling().isNull(), true);
2109     QCOMPARE(titleBoxElement.localName(), QString("text-box"));
2110 
2111     // <text:p> for the title text-box
2112     KoXmlElement titleParElement;
2113     titleParElement = titleBoxElement.firstChild().toElement();
2114     QCOMPARE(titleParElement.isNull(), false);
2115     QCOMPARE(titleParElement.isElement(), true);
2116     QCOMPARE(titleParElement.parentNode().isNull(), false);
2117     QCOMPARE(titleParElement.parentNode() == titleBoxElement, true);
2118     QCOMPARE(KoXml::childNodesCount(titleParElement), 1);
2119     QCOMPARE(titleParElement.firstChild().isNull(), false);
2120     QCOMPARE(titleParElement.lastChild().isNull(), false);
2121     QCOMPARE(titleParElement.previousSibling().isNull(), true);
2122     QCOMPARE(titleParElement.nextSibling().isNull(), true);
2123     QCOMPARE(titleParElement.localName(), QString("p"));
2124     QCOMPARE(titleParElement.attributeNS(textNS, "style-name", ""), QString("P1"));
2125     QCOMPARE(titleParElement.text(), QString("Foobar"));
2126 
2127     // <draw:frame> for the subtitle frame
2128     KoXmlElement subtitleFrameElement;
2129     subtitleFrameElement = titleFrameElement.nextSibling().toElement();
2130     QCOMPARE(subtitleFrameElement.isNull(), false);
2131     QCOMPARE(subtitleFrameElement.isElement(), true);
2132     QCOMPARE(subtitleFrameElement.parentNode().isNull(), false);
2133     QCOMPARE(subtitleFrameElement.parentNode() == titlePageElement, true);
2134     QCOMPARE(KoXml::childNodesCount(subtitleFrameElement), 1);
2135     QCOMPARE(subtitleFrameElement.firstChild().isNull(), false);
2136     QCOMPARE(subtitleFrameElement.lastChild().isNull(), false);
2137     QCOMPARE(subtitleFrameElement.previousSibling().isNull(), false);
2138     QCOMPARE(subtitleFrameElement.nextSibling().isNull(), false);
2139     QCOMPARE(subtitleFrameElement.localName(), QString("frame"));
2140     QCOMPARE(subtitleFrameElement.attributeNS(presentationNS, "style-name", ""), QString("pr2"));
2141     QCOMPARE(subtitleFrameElement.attributeNS(presentationNS, "class", ""), QString("subtitle"));
2142     QCOMPARE(subtitleFrameElement.hasAttributeNS(presentationNS, "user-transformed"), false);
2143     QCOMPARE(subtitleFrameElement.attributeNS(drawNS, "text-style-name", ""), QString("P3"));
2144     QCOMPARE(subtitleFrameElement.attributeNS(drawNS, "layer", ""), QString("layout"));
2145     QCOMPARE(subtitleFrameElement.attributeNS(svgNS, "width", ""), QString("23.912cm"));
2146     QCOMPARE(subtitleFrameElement.attributeNS(svgNS, "height", ""), QString("13.231cm"));
2147     QCOMPARE(subtitleFrameElement.attributeNS(svgNS, "x", ""), QString("2.058cm"));
2148     QCOMPARE(subtitleFrameElement.attributeNS(svgNS, "y", ""), QString("5.838cm"));
2149 
2150     // <draw:text-box> of the subtitle frame
2151     KoXmlElement subtitleBoxElement;
2152     subtitleBoxElement = subtitleFrameElement.firstChild().toElement();
2153     QCOMPARE(subtitleBoxElement.isNull(), false);
2154     QCOMPARE(subtitleBoxElement.isElement(), true);
2155     QCOMPARE(subtitleBoxElement.parentNode().isNull(), false);
2156     QCOMPARE(subtitleBoxElement.parentNode() == subtitleFrameElement, true);
2157     QCOMPARE(KoXml::childNodesCount(subtitleBoxElement), 1);
2158     QCOMPARE(subtitleBoxElement.firstChild().isNull(), false);
2159     QCOMPARE(subtitleBoxElement.lastChild().isNull(), false);
2160     QCOMPARE(subtitleBoxElement.previousSibling().isNull(), true);
2161     QCOMPARE(subtitleBoxElement.nextSibling().isNull(), true);
2162     QCOMPARE(subtitleBoxElement.localName(), QString("text-box"));
2163 
2164     // <text:p> for the subtitle text-box
2165     KoXmlElement subtitleParElement;
2166     subtitleParElement = subtitleBoxElement.firstChild().toElement();
2167     QCOMPARE(subtitleParElement.isNull(), false);
2168     QCOMPARE(subtitleParElement.isElement(), true);
2169     QCOMPARE(subtitleParElement.parentNode().isNull(), false);
2170     QCOMPARE(subtitleParElement.parentNode() == subtitleBoxElement, true);
2171     QCOMPARE(KoXml::childNodesCount(subtitleParElement), 1);
2172     QCOMPARE(subtitleParElement.firstChild().isNull(), false);
2173     QCOMPARE(subtitleParElement.lastChild().isNull(), false);
2174     QCOMPARE(subtitleParElement.previousSibling().isNull(), true);
2175     QCOMPARE(subtitleParElement.nextSibling().isNull(), true);
2176     QCOMPARE(subtitleParElement.localName(), QString("p"));
2177     QCOMPARE(subtitleParElement.attributeNS(textNS, "style-name", ""), QString("P3"));
2178     QCOMPARE(subtitleParElement.text(), QString("Foo"));
2179 }
2180 
testSimpleOpenDocumentFormula()2181 void TestXmlReaderWithoutSpaces::testSimpleOpenDocumentFormula()
2182 {
2183     QString errorMsg;
2184     int errorLine = 0;
2185     int errorColumn = 0;
2186 
2187     QBuffer xmldevice;
2188     xmldevice.open(QIODevice::WriteOnly);
2189     QTextStream xmlstream(&xmldevice);
2190 
2191     // content.xml from a simple OpenDocument formula
2192     // this is essentially MathML
2193     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
2194     xmlstream << "<!DOCTYPE math:math PUBLIC \"-//OpenOffice.org//DTD Modified W3C MathML 1.01//EN\" \"math.dtd\">";
2195     xmlstream << "<math:math xmlns:math=\"http://www.w3.org/1998/Math/MathML\">";
2196     xmlstream  << "<math:semantics>";
2197     xmlstream   << "<math:mrow>";
2198     xmlstream    << "<math:mi>E</math:mi>";
2199     xmlstream    << "<math:mo math:stretchy=\"false\">=</math:mo>";
2200     xmlstream    << "<math:msup>";
2201     xmlstream     << "<math:mi math:fontstyle=\"italic\">mc</math:mi>";
2202     xmlstream     << "<math:mn>2</math:mn>";
2203     xmlstream    << "</math:msup>";
2204     xmlstream   << "</math:mrow>";
2205     xmlstream   << "<math:annotation math:encoding=\"StarMath 5.0\">E  =  mc^2 </math:annotation>";
2206     xmlstream  << "</math:semantics>";
2207     xmlstream << "</math:math>";
2208     xmldevice.close();
2209 
2210     KoXmlDocument doc(false);
2211     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
2212     QCOMPARE(errorMsg.isEmpty(), true);
2213     QCOMPARE(errorLine, 0);
2214     QCOMPARE(errorColumn, 0);
2215 
2216     const char* mathNS = "http://www.w3.org/1998/Math/MathML";
2217 
2218     // <math:math>
2219     KoXmlElement mathElement;
2220     mathElement = doc.documentElement();
2221     QCOMPARE(mathElement.isNull(), false);
2222     QCOMPARE(mathElement.isElement(), true);
2223     QCOMPARE(mathElement.parentNode().isNull(), false);
2224     QCOMPARE(mathElement.parentNode().toDocument() == doc, true);
2225     QCOMPARE(mathElement.firstChild().isNull(), false);
2226     QCOMPARE(mathElement.lastChild().isNull(), false);
2227     QCOMPARE(mathElement.previousSibling().isNull(), false);
2228     QCOMPARE(mathElement.nextSibling().isNull(), true);
2229     QCOMPARE(mathElement.localName(), QString("math"));
2230 
2231     // <math:semantics>
2232     KoXmlElement semanticsElement;
2233     semanticsElement = KoXml::namedItemNS(mathElement, mathNS, "semantics");
2234     QCOMPARE(semanticsElement.isNull(), false);
2235     QCOMPARE(semanticsElement.isElement(), true);
2236     QCOMPARE(semanticsElement.parentNode().isNull(), false);
2237     QCOMPARE(semanticsElement.parentNode().toElement() == mathElement, true);
2238     QCOMPARE(semanticsElement.firstChild().isNull(), false);
2239     QCOMPARE(semanticsElement.lastChild().isNull(), false);
2240     QCOMPARE(semanticsElement.previousSibling().isNull(), true);
2241     QCOMPARE(semanticsElement.nextSibling().isNull(), true);
2242     QCOMPARE(semanticsElement.localName(), QString("semantics"));
2243 
2244     // the same <math:semantics> but without namedItemNS
2245     KoXmlElement semantics2Element;
2246     semantics2Element = mathElement.firstChild().toElement();
2247     QCOMPARE(semantics2Element.isNull(), false);
2248     QCOMPARE(semantics2Element.isElement(), true);
2249     QCOMPARE(semantics2Element.parentNode().isNull(), false);
2250     QCOMPARE(semantics2Element.parentNode().toElement() == mathElement, true);
2251     QCOMPARE(semantics2Element.firstChild().isNull(), false);
2252     QCOMPARE(semantics2Element.lastChild().isNull(), false);
2253     QCOMPARE(semantics2Element.previousSibling().isNull(), true);
2254     QCOMPARE(semantics2Element.nextSibling().isNull(), true);
2255     QCOMPARE(semantics2Element.localName(), QString("semantics"));
2256 
2257     // <math:mrow>
2258     KoXmlElement mrowElement;
2259     mrowElement = semanticsElement.firstChild().toElement();
2260     QCOMPARE(mrowElement.isNull(), false);
2261     QCOMPARE(mrowElement.isElement(), true);
2262     QCOMPARE(mrowElement.parentNode().isNull(), false);
2263     QCOMPARE(mrowElement.parentNode().toElement() == semanticsElement, true);
2264     QCOMPARE(mrowElement.firstChild().isNull(), false);
2265     QCOMPARE(mrowElement.lastChild().isNull(), false);
2266     QCOMPARE(mrowElement.previousSibling().isNull(), true);
2267     QCOMPARE(mrowElement.nextSibling().isNull(), false);
2268     QCOMPARE(mrowElement.localName(), QString("mrow"));
2269 
2270     // <math:mi> for "E"
2271     KoXmlElement miElement;
2272     miElement = mrowElement.firstChild().toElement();
2273     QCOMPARE(miElement.isNull(), false);
2274     QCOMPARE(miElement.isElement(), true);
2275     QCOMPARE(miElement.parentNode().isNull(), false);
2276     QCOMPARE(miElement.parentNode().toElement() == mrowElement, true);
2277     QCOMPARE(miElement.firstChild().isNull(), false);
2278     QCOMPARE(miElement.lastChild().isNull(), false);
2279     QCOMPARE(miElement.previousSibling().isNull(), true);
2280     QCOMPARE(miElement.nextSibling().isNull(), false);
2281     QCOMPARE(miElement.localName(), QString("mi"));
2282 
2283     // <math:mo> for "="
2284     KoXmlElement moElement;
2285     moElement = miElement.nextSibling().toElement();
2286     QCOMPARE(moElement.isNull(), false);
2287     QCOMPARE(moElement.isElement(), true);
2288     QCOMPARE(moElement.parentNode().isNull(), false);
2289     QCOMPARE(moElement.parentNode().toElement() == mrowElement, true);
2290     QCOMPARE(moElement.firstChild().isNull(), false);
2291     QCOMPARE(moElement.lastChild().isNull(), false);
2292     QCOMPARE(moElement.previousSibling().isNull(), false);
2293     QCOMPARE(moElement.nextSibling().isNull(), false);
2294     QCOMPARE(moElement.localName(), QString("mo"));
2295     QCOMPARE(moElement.attributeNS(mathNS, "stretchy", ""), QString("false"));
2296 
2297     // <math:msup> for "mc" and superscripted "2"
2298     KoXmlElement msupElement;
2299     msupElement = moElement.nextSibling().toElement();
2300     QCOMPARE(msupElement.isNull(), false);
2301     QCOMPARE(msupElement.isElement(), true);
2302     QCOMPARE(msupElement.parentNode().isNull(), false);
2303     QCOMPARE(msupElement.parentNode().toElement() == mrowElement, true);
2304     QCOMPARE(msupElement.firstChild().isNull(), false);
2305     QCOMPARE(msupElement.lastChild().isNull(), false);
2306     QCOMPARE(msupElement.previousSibling().isNull(), false);
2307     QCOMPARE(msupElement.nextSibling().isNull(), true);
2308     QCOMPARE(msupElement.localName(), QString("msup"));
2309 
2310     // <math:mi> inside the <math:msup> for "mc"
2311     KoXmlElement mcElement;
2312     mcElement = msupElement.firstChild().toElement();
2313     QCOMPARE(mcElement.isNull(), false);
2314     QCOMPARE(mcElement.isElement(), true);
2315     QCOMPARE(mcElement.parentNode().isNull(), false);
2316     QCOMPARE(mcElement.parentNode().toElement() == msupElement, true);
2317     QCOMPARE(mcElement.firstChild().isNull(), false);
2318     QCOMPARE(mcElement.lastChild().isNull(), false);
2319     QCOMPARE(mcElement.previousSibling().isNull(), true);
2320     QCOMPARE(mcElement.nextSibling().isNull(), false);
2321     QCOMPARE(mcElement.localName(), QString("mi"));
2322     QCOMPARE(mcElement.text(), QString("mc"));
2323     QCOMPARE(mcElement.attributeNS(mathNS, "fontstyle", ""), QString("italic"));
2324 
2325     // <math:mn> inside the <math:msup> for "2" (superscript)
2326     KoXmlElement mnElement;
2327     mnElement = mcElement.nextSibling().toElement();
2328     QCOMPARE(mnElement.isNull(), false);
2329     QCOMPARE(mnElement.isElement(), true);
2330     QCOMPARE(mnElement.parentNode().isNull(), false);
2331     QCOMPARE(mnElement.parentNode().toElement() == msupElement, true);
2332     QCOMPARE(mnElement.firstChild().isNull(), false);
2333     QCOMPARE(mnElement.lastChild().isNull(), false);
2334     QCOMPARE(mnElement.previousSibling().isNull(), false);
2335     QCOMPARE(mnElement.nextSibling().isNull(), true);
2336     QCOMPARE(mnElement.localName(), QString("mn"));
2337     QCOMPARE(mnElement.text(), QString("2"));
2338 
2339     // <math:annotation>
2340     KoXmlElement annotationElement;
2341     annotationElement = semanticsElement.lastChild().toElement();
2342     QCOMPARE(annotationElement.isNull(), false);
2343     QCOMPARE(annotationElement.isElement(), true);
2344     QCOMPARE(annotationElement.parentNode().isNull(), false);
2345     QCOMPARE(annotationElement.parentNode().toElement() == semanticsElement, true);
2346     QCOMPARE(annotationElement.firstChild().isNull(), false);
2347     QCOMPARE(annotationElement.lastChild().isNull(), false);
2348     QCOMPARE(annotationElement.previousSibling().isNull(), false);
2349     QCOMPARE(annotationElement.nextSibling().isNull(), true);
2350     QCOMPARE(annotationElement.localName(), QString("annotation"));
2351     QCOMPARE(annotationElement.text(), QString("E  =  mc^2 "));
2352     QCOMPARE(annotationElement.attributeNS(mathNS, "encoding", ""), QString("StarMath 5.0"));
2353 }
2354 
testLargeOpenDocumentSpreadsheet()2355 void TestXmlReaderWithoutSpaces::testLargeOpenDocumentSpreadsheet()
2356 {
2357     QString errorMsg;
2358     int errorLine = 0;
2359     int errorColumn = 0;
2360 
2361     int sheetCount = 4;
2362     int rowCount = 200;
2363     int colCount = 200 / 16;
2364 
2365     QBuffer xmldevice;
2366     xmldevice.open(QIODevice::WriteOnly);
2367     QTextStream xmlstream(&xmldevice);
2368 
2369     // content.xml
2370     xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
2371     xmlstream << "<office:document-content ";
2372     xmlstream << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" ";
2373     xmlstream << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" ";
2374     xmlstream << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" >";
2375     xmlstream << "<office:body>";
2376     xmlstream << "<office:spreadsheet>";
2377     for (int i = 0; i < sheetCount; i++) {
2378         QString sheetName = QString("Sheet%1").arg(i + 1);
2379         xmlstream << "<table:table table:name=\"" << sheetName;
2380         xmlstream << "\" table:print=\"false\">";
2381         for (int j = 0; j < rowCount; j++) {
2382             xmlstream << "<table:table-row>";
2383             for (int k = 0; k < colCount; k++) {
2384                 xmlstream << "<table:table-cell office:value-type=\"string\">";
2385                 xmlstream << "<text:p>Hello, world</text:p>";
2386                 xmlstream << "</table:table-cell>";
2387             }
2388             xmlstream << "</table:table-row>";
2389         }
2390         xmlstream << "</table:table>";
2391     }
2392     xmlstream << "</office:spreadsheet>";
2393     xmlstream << "</office:body>";
2394     xmlstream << "</office:document-content>";
2395     xmldevice.close();
2396 
2397     printf("Raw XML size: %lld KB\n", xmldevice.size() / 1024);
2398 
2399 
2400     QTime timer;
2401 
2402 #if 0
2403     // just to test parsing speed with plain dumb handler
2404     QXmlStreamReader *reader = new QXmlStreamReader(xmldevice);
2405     reader->setNamespaceProcessing(true);
2406     timer.start();
2407     ParseError error = parseDocument(*reader, doc);
2408     printf("Large spreadsheet: QXmlStreamReader parsing time is %d ms\n", timer.elapsed());
2409     delete reader;
2410     xmldevice.seek(0);
2411 #endif
2412 
2413     KoXmlDocument doc(false);
2414 
2415     timer.start();
2416     QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
2417     QCOMPARE(errorMsg.isEmpty(), true);
2418     QCOMPARE(errorLine, 0);
2419     QCOMPARE(errorColumn, 0);
2420 
2421     if (!errorMsg.isEmpty()) {
2422         qDebug("Error: %s", qPrintable(errorMsg));
2423         return;
2424     }
2425 
2426     printf("Large spreadsheet: KoXmlDocument parsing time is %d ms\n", timer.elapsed());
2427 
2428     // release memory taken by the XML document content
2429     //xmlstream.setDevice( 0 );
2430 
2431     // namespaces that will be used
2432     QString officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
2433     QString tableNS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
2434 
2435     // <office:document-content>
2436     KoXmlElement contentElement;
2437     contentElement = doc.documentElement();
2438     QCOMPARE(contentElement.isNull(), false);
2439     QCOMPARE(contentElement.isElement(), true);
2440     QCOMPARE(contentElement.localName(), QString("document-content"));
2441 
2442     // <office:body>
2443     KoXmlElement bodyElement;
2444     bodyElement = contentElement.firstChild().toElement();
2445     QCOMPARE(bodyElement.isNull(), false);
2446     QCOMPARE(bodyElement.isElement(), true);
2447     QCOMPARE(bodyElement.localName(), QString("body"));
2448 
2449     // <office:spreadsheet>
2450     KoXmlElement spreadsheetElement;
2451     spreadsheetElement = bodyElement.firstChild().toElement();
2452     QCOMPARE(spreadsheetElement.isNull(), false);
2453     QCOMPARE(spreadsheetElement.isElement(), true);
2454     QCOMPARE(spreadsheetElement.localName(), QString("spreadsheet"));
2455 
2456     // now we visit every sheet, every row, every cell
2457     timer.start();
2458     KoXmlElement tableElement;
2459     tableElement = spreadsheetElement.firstChild().toElement();
2460     for (int table = 0; table < sheetCount; table++) {
2461         QString tableName = QString("Sheet%1").arg(table + 1);
2462         QCOMPARE(tableElement.isNull(), false);
2463         QCOMPARE(tableElement.isElement(), true);
2464         QCOMPARE(tableElement.localName(), QString("table"));
2465         QCOMPARE(tableElement.hasAttributeNS(tableNS, "name"), true);
2466         QCOMPARE(tableElement.attributeNS(tableNS, "name", ""), tableName);
2467         QCOMPARE(tableElement.attributeNS(tableNS, "print", ""), QString("false"));
2468 
2469         // load everything for this table
2470         //KoXml::load( tableElement, 99 );
2471 
2472         QCOMPARE(tableElement.parentNode().isNull(), false);
2473         QCOMPARE(tableElement.parentNode() == spreadsheetElement, true);
2474         QCOMPARE(tableElement.firstChild().isNull(), false);
2475         QCOMPARE(tableElement.lastChild().isNull(), false);
2476 
2477         KoXmlElement rowElement;
2478         rowElement = tableElement.firstChild().toElement();
2479         for (int row = 0; row < rowCount; row++) {
2480             QCOMPARE(rowElement.isNull(), false);
2481             QCOMPARE(rowElement.isElement(), true);
2482             QCOMPARE(rowElement.localName(), QString("table-row"));
2483             QCOMPARE(rowElement.parentNode().isNull(), false);
2484             QCOMPARE(rowElement.parentNode() == tableElement, true);
2485             QCOMPARE(rowElement.firstChild().isNull(), false);
2486             QCOMPARE(rowElement.lastChild().isNull(), false);
2487 
2488             KoXmlElement cellElement;
2489             cellElement = rowElement.firstChild().toElement();
2490             for (int col = 0; col < colCount; col++) {
2491                 QCOMPARE(cellElement.isNull(), false);
2492                 QCOMPARE(cellElement.isElement(), true);
2493                 QCOMPARE(cellElement.localName(), QString("table-cell"));
2494                 QCOMPARE(cellElement.text(), QString("Hello, world"));
2495                 QCOMPARE(cellElement.hasAttributeNS(officeNS, "value-type"), true);
2496                 QCOMPARE(cellElement.attributeNS(officeNS, "value-type", ""), QString("string"));
2497                 QCOMPARE(cellElement.parentNode().isNull(), false);
2498                 QCOMPARE(cellElement.parentNode() == rowElement, true);
2499                 QCOMPARE(cellElement.firstChild().isNull(), false);
2500                 QCOMPARE(cellElement.lastChild().isNull(), false);
2501                 cellElement = cellElement.nextSibling().toElement();
2502             }
2503 
2504             //KoXml::unload( rowElement );
2505             rowElement = rowElement.nextSibling().toElement();
2506         }
2507 
2508         KoXml::unload(tableElement);
2509         tableElement = tableElement.nextSibling().toElement();
2510     }
2511 
2512     printf("Large spreadsheet: iterating time is %d ms\n", timer.elapsed());
2513 }
2514 
testExternalOpenDocumentSpreadsheet(const QString & filename)2515 void TestXmlReaderWithoutSpaces::testExternalOpenDocumentSpreadsheet(const QString& filename)
2516 {
2517     QProcess unzip;
2518     QStringList arguments;
2519     arguments << "-o" << filename << "content.xml";
2520 
2521     printf("Unzipping content.xml from %s...\n", qPrintable(filename));
2522 
2523     unzip.start("unzip", arguments);
2524     if (!unzip.waitForStarted()) {
2525         printf("Error: can't invoke unzip. Check your PATH and installation!\n\n");
2526         return;
2527     }
2528 
2529     if (!unzip.waitForFinished()) {
2530         printf("Error: unzip failed, can't continue!\n\n");
2531         return;
2532     }
2533 
2534     printf("Procesing content.xml....\n");
2535 
2536     QString errorMsg;
2537     int errorLine = 0;
2538     int errorColumn = 0;
2539 
2540     QFile xmlfile("content.xml");
2541     if (!xmlfile.open(QFile::ReadOnly)) {
2542         printf("Can not open file '%s'\n", qPrintable(filename));
2543         return;
2544     }
2545 
2546     printf("Test external file: %s   %lld KB\n", qPrintable(filename), xmlfile.size() / 1024);
2547 
2548     QTime timer;
2549     timer.start();
2550 
2551     KoXmlDocument doc(false);
2552 
2553     QCOMPARE(KoXml::setDocument(doc, &xmlfile, true, &errorMsg, &errorLine, &errorColumn), true);
2554     QCOMPARE(errorMsg.isEmpty(), true);
2555     QCOMPARE(errorLine, 0);
2556     QCOMPARE(errorColumn, 0);
2557 
2558     printf("External spreadsheet: parsing time is %d ms\n", timer.elapsed());
2559 
2560     // namespaces that will be used
2561     QString officeNS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
2562     QString tableNS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
2563 
2564     // <office:document-content>
2565     KoXmlElement contentElement;
2566     contentElement = doc.documentElement();
2567     QCOMPARE(contentElement.isNull(), false);
2568     QCOMPARE(contentElement.isElement(), true);
2569     QCOMPARE(contentElement.localName(), QString("document-content"));
2570 
2571     long totalCellCount = 0;
2572 
2573     KoXmlElement bodyElement;
2574     forEachElement(bodyElement, contentElement) {
2575         // <office:body>
2576         if (bodyElement.localName() != QString("body"))
2577             continue;
2578 
2579         // now we iterate inside the body
2580         timer.start();
2581 
2582         // <office:spreadsheet>
2583         KoXmlElement spreadsheetElement;
2584         spreadsheetElement = bodyElement.firstChild().toElement();
2585         QCOMPARE(spreadsheetElement.isNull(), false);
2586         QCOMPARE(spreadsheetElement.isElement(), true);
2587         QCOMPARE(spreadsheetElement.localName(), QString("spreadsheet"));
2588 
2589         // now we visit every sheet
2590         long tableCount = -1;
2591         KoXmlElement tableElement;
2592         tableElement = spreadsheetElement.firstChild().toElement();
2593         for (;;) {
2594             if (tableElement.isNull())
2595                 break;
2596 
2597             if (tableElement.localName() != QString("table")) {
2598                 tableElement = tableElement.nextSibling().toElement();
2599                 continue;
2600             }
2601 
2602             QString tableName = tableElement.attributeNS(tableNS, "name", "");
2603             tableCount++;
2604 
2605             printf(" sheet #%ld (%s): ", tableCount + 1, qPrintable(tableName));
2606 
2607             // use to preload everything in this sheet, will slow it down!
2608             // KoXml::load( tableElement, 50 );
2609 
2610             long rowCount = -1;
2611             long cellCount = -1;
2612 
2613             KoXmlElement rowElement;
2614             rowElement = tableElement.firstChild().toElement();
2615             for (;;) {
2616                 if (rowElement.isNull())
2617                     break;
2618 
2619                 if (rowElement.localName() != QString("table-row")) {
2620                     rowElement = rowElement.nextSibling().toElement();
2621                     continue;
2622                 }
2623 
2624                 rowCount++;
2625                 KoXml::load(rowElement, 4);
2626 
2627                 QCOMPARE(rowElement.isElement(), true);
2628                 QCOMPARE(rowElement.localName(), QString("table-row"));
2629                 QCOMPARE(rowElement.parentNode().isNull(), false);
2630                 QCOMPARE(rowElement.parentNode() == tableElement, true);
2631 
2632                 KoXmlElement cellElement;
2633                 cellElement = rowElement.firstChild().toElement();
2634                 for (; ;) {
2635                     if (cellElement.isNull())
2636                         break;
2637 
2638                     if (cellElement.localName() != QString("table-cell")) {
2639                         cellElement = cellElement.nextSibling().toElement();
2640                         continue;
2641                     }
2642 
2643                     cellCount++;
2644 
2645                     QCOMPARE(cellElement.isNull(), false);
2646                     QCOMPARE(cellElement.isElement(), true);
2647                     QCOMPARE(cellElement.localName(), QString("table-cell"));
2648                     QString text1 = cellElement.text();
2649                     QString text2 = cellElement.text();
2650                     QCOMPARE(text1, text2);
2651                     QString type1 = cellElement.attributeNS(officeNS, "value-type", QString());
2652                     QString type2 = cellElement.attributeNS(officeNS, "value-type", QString());
2653                     QCOMPARE(type1, type2);
2654                     QString style1 = cellElement.attributeNS(tableNS, "style-name", QString());
2655                     QString style2 = cellElement.attributeNS(tableNS, "style-name", QString());
2656                     QCOMPARE(style1, style2);
2657 
2658                     QCOMPARE(cellElement.parentNode().isNull(), false);
2659                     QCOMPARE(cellElement.parentNode() == rowElement, true);
2660 
2661                     cellElement = cellElement.nextSibling().toElement();
2662                 }
2663 
2664 
2665                 // better not to unload, freeing memory takes time
2666                 KoXml::unload(rowElement);
2667 
2668                 rowElement = rowElement.nextSibling().toElement();
2669             }
2670 
2671             printf(" %ld rows, %ld cells\n", rowCount + 1, cellCount + 1);
2672             totalCellCount += (cellCount + 1);
2673 
2674             // IMPORTANT: helps minimizing memory usage !!
2675             // we do not need that element anymore, so just throw it away
2676             KoXml::unload(tableElement);
2677 
2678             tableElement = tableElement.nextSibling().toElement();
2679         }
2680 
2681         KoXml::unload(spreadsheetElement);
2682     }
2683 
2684     printf("Total number of cells: %ld\n", totalCellCount);
2685 
2686     int elapsed = timer.elapsed();
2687     printf("External spreadsheet: iterating time is %d ms\n", elapsed);
2688     if (elapsed > 0)
2689         printf("  approx. %ld cells/second\n", totalCellCount*1000 / elapsed);
2690 
2691     // uncomment to check the XML
2692     xmlfile.remove();
2693 }
2694 
2695 QTEST_GUILESS_MAIN(TestXmlReaderWithoutSpaces)
2696 #include <TestXmlReaderWithoutSpaces.moc>
2697 
2698