summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Parser/Attribute.h8
-rw-r--r--Swiften/Parser/AttributeMap.cpp4
-rw-r--r--Swiften/Parser/AttributeMap.h1
-rw-r--r--Swiften/Parser/ExpatParser.cpp57
-rw-r--r--Swiften/Parser/LibXMLParser.cpp33
-rw-r--r--Swiften/Parser/UnitTest/AttributeMapTest.cpp17
-rw-r--r--Swiften/Parser/UnitTest/XMLParserTest.cpp59
-rw-r--r--Swiften/Parser/XMLParserClient.cpp6
-rw-r--r--Swiften/Parser/XMLParserClient.h8
9 files changed, 160 insertions, 33 deletions
diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h
index f54317e..07e63b4 100644
--- a/Swiften/Parser/Attribute.h
+++ b/Swiften/Parser/Attribute.h
@@ -14,6 +14,9 @@ namespace Swift {
14 Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { 14 Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) {
15 } 15 }
16 16
17 Attribute(const std::string& name, const std::string& ns, const std::string& prefix) : name(name), ns(ns), prefix(prefix) {
18 }
19
17 const std::string& getName() const { 20 const std::string& getName() const {
18 return name; 21 return name;
19 } 22 }
@@ -22,6 +25,10 @@ namespace Swift {
22 return ns; 25 return ns;
23 } 26 }
24 27
28 const std::string& getPrefix() const {
29 return prefix;
30 }
31
25 bool operator==(const Attribute& o) const { 32 bool operator==(const Attribute& o) const {
26 return o.name == name && o.ns == ns; 33 return o.name == name && o.ns == ns;
27 } 34 }
@@ -29,5 +36,6 @@ namespace Swift {
29 private: 36 private:
30 std::string name; 37 std::string name;
31 std::string ns; 38 std::string ns;
39 std::string prefix;
32 }; 40 };
33} 41}
diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp
index f6767de..7814a64 100644
--- a/Swiften/Parser/AttributeMap.cpp
+++ b/Swiften/Parser/AttributeMap.cpp
@@ -54,3 +54,7 @@ boost::optional<std::string> AttributeMap::getAttributeValue(const std::string&
54void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { 54void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) {
55 attributes.push_back(Entry(Attribute(name, ns), value)); 55 attributes.push_back(Entry(Attribute(name, ns), value));
56} 56}
57
58void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value) {
59 attributes.push_back(Entry(Attribute(name, ns, prefix), value));
60}
diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h
index 804d6aa..26d5826 100644
--- a/Swiften/Parser/AttributeMap.h
+++ b/Swiften/Parser/AttributeMap.h
@@ -43,6 +43,7 @@ namespace Swift {
43 boost::optional<std::string> getAttributeValue(const std::string&) const; 43 boost::optional<std::string> getAttributeValue(const std::string&) const;
44 44
45 void addAttribute(const std::string& name, const std::string& ns, const std::string& value); 45 void addAttribute(const std::string& name, const std::string& ns, const std::string& value);
46 void addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value);
46 47
47 const std::vector<Entry>& getEntries() const { 48 const std::vector<Entry>& getEntries() const {
48 return attributes; 49 return attributes;
diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp
index 640d561..6c3845a 100644
--- a/Swiften/Parser/ExpatParser.cpp
+++ b/Swiften/Parser/ExpatParser.cpp
@@ -11,6 +11,8 @@
11#include <memory> 11#include <memory>
12#include <string> 12#include <string>
13 13
14#include <boost/algorithm/string.hpp>
15
14#include <expat.h> 16#include <expat.h>
15 17
16#include <Swiften/Base/String.h> 18#include <Swiften/Base/String.h>
@@ -18,6 +20,33 @@
18 20
19#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" 21#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
20 22
23namespace {
24struct XmlInfo {
25 std::string prefix;
26 std::string uri;
27 std::string name;
28};
29
30XmlInfo splitExpatInfo(const std::string& s, char sep) {
31 // name
32 // uri|name
33 // uri|name|prefix
34 std::vector<std::string> v;
35 boost::split(v, s, [sep](char c) {return c == sep; });
36 switch (v.size()) {
37 case 1:
38 return{ "", "", std::move(v[0]) };
39 case 2:
40 return{ "", std::move(v[0]), std::move(v[1]) };
41 case 3:
42 return{ std::move(v[2]), std::move(v[0]), std::move(v[1]) };
43 default:
44 return{ "", "", "" };
45 }
46}
47}
48
49
21namespace Swift { 50namespace Swift {
22 51
23static const char NAMESPACE_SEPARATOR = '\x01'; 52static const char NAMESPACE_SEPARATOR = '\x01';
@@ -27,33 +56,24 @@ struct ExpatParser::Private {
27}; 56};
28 57
29static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { 58static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) {
30 std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); 59 auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR);
31 if (nsTagPair.second == "") { 60
32 nsTagPair.second = nsTagPair.first;
33 nsTagPair.first = "";
34 }
35 AttributeMap attributeValues; 61 AttributeMap attributeValues;
36 const XML_Char** currentAttribute = attributes; 62 const XML_Char** currentAttribute = attributes;
37 while (*currentAttribute) { 63 while (*currentAttribute) {
38 std::pair<std::string,std::string> nsAttributePair = String::getSplittedAtFirst(*currentAttribute, NAMESPACE_SEPARATOR); 64 auto attribInfo = splitExpatInfo(*currentAttribute, NAMESPACE_SEPARATOR);
39 if (nsAttributePair.second == "") { 65 attributeValues.addAttribute(attribInfo.name, attribInfo.uri, attribInfo.prefix, std::string(*(currentAttribute+1)));
40 nsAttributePair.second = nsAttributePair.first;
41 nsAttributePair.first = "";
42 }
43 attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1)));
44 currentAttribute += 2; 66 currentAttribute += 2;
45 } 67 }
46 68
47 static_cast<XMLParser*>(parser)->getClient()->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues); 69 auto* client = static_cast<XMLParser*>(parser)->getClient();
70 client->handleStartElementPrefix(elemInfo.prefix, elemInfo.uri, elemInfo.name, elemInfo.name, elemInfo.uri, attributeValues);
71 client->handleStartElement(elemInfo.name, elemInfo.uri, attributeValues);
48} 72}
49 73
50static void handleEndElement(void* parser, const XML_Char* name) { 74static void handleEndElement(void* parser, const XML_Char* name) {
51 std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); 75 auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR);
52 if (nsTagPair.second == "") { 76 static_cast<XMLParser*>(parser)->getClient()->handleEndElement(elemInfo.name, elemInfo.uri);
53 nsTagPair.second = nsTagPair.first;
54 nsTagPair.first = "";
55 }
56 static_cast<XMLParser*>(parser)->getClient()->handleEndElement(nsTagPair.second, nsTagPair.first);
57} 77}
58 78
59static void handleCharacterData(void* parser, const XML_Char* data, int len) { 79static void handleCharacterData(void* parser, const XML_Char* data, int len) {
@@ -88,6 +108,7 @@ static void handleDoctypeDeclaration(void* parser, const XML_Char* /*doctypeName
88 108
89ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { 109ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) {
90 p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); 110 p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR);
111 XML_SetReturnNSTriplet(p->parser_, true);
91 XML_SetUserData(p->parser_, this); 112 XML_SetUserData(p->parser_, this);
92 XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement); 113 XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement);
93 XML_SetCharacterDataHandler(p->parser_, handleCharacterData); 114 XML_SetCharacterDataHandler(p->parser_, handleCharacterData);
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp
index 4e02059..71515a7 100644
--- a/Swiften/Parser/LibXMLParser.cpp
+++ b/Swiften/Parser/LibXMLParser.cpp
@@ -17,6 +17,12 @@
17#include <Swiften/Base/Log.h> 17#include <Swiften/Base/Log.h>
18#include <Swiften/Parser/XMLParserClient.h> 18#include <Swiften/Parser/XMLParserClient.h>
19 19
20namespace {
21std::string asString(const unsigned char* s) {
22 return s ? std::string(reinterpret_cast<const char*>(s)) : std::string();
23}
24}
25
20namespace Swift { 26namespace Swift {
21 27
22struct LibXMLParser::Private { 28struct LibXMLParser::Private {
@@ -24,34 +30,39 @@ struct LibXMLParser::Private {
24 xmlParserCtxtPtr context_; 30 xmlParserCtxtPtr context_;
25}; 31};
26 32
27static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int nbNamespaces, const xmlChar** namespaces, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { 33static void handleStartElement(void* parser, const xmlChar* name, const xmlChar* prefix, const xmlChar* xmlns, int nbNamespaces, const xmlChar** namespaces, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) {
28 AttributeMap attributeValues; 34 AttributeMap attributeValues;
29 if (nbDefaulted != 0) { 35 if (nbDefaulted != 0) {
30 // Just because i don't understand what this means yet :-) 36 // Just because i don't understand what this means yet :-)
31 SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element" << std::endl; 37 SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element" << std::endl;
32 } 38 }
33 for (int i = 0; i < nbAttributes*5; i += 5) { 39 for (int i = 0; i < nbAttributes*5; i += 5) {
34 std::string attributeNS = ""; 40 std::string attributeName = asString(attributes[i]);
35 if (attributes[i+2]) { 41 std::string attributePrefix = asString(attributes[i+1]);
36 attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); 42 std::string attributeNS = asString(attributes[i+2]);
37 }
38 assert(attributes[i+4] >= attributes[i+3]); 43 assert(attributes[i+4] >= attributes[i+3]);
39 attributeValues.addAttribute( 44 attributeValues.addAttribute(
40 std::string(reinterpret_cast<const char*>(attributes[i])), 45 attributeName,
41 attributeNS, 46 attributeNS,
47 attributePrefix,
42 std::string(reinterpret_cast<const char*>(attributes[i+3]), 48 std::string(reinterpret_cast<const char*>(attributes[i+3]),
43 static_cast<size_t>(attributes[i+4]-attributes[i+3]))); 49 static_cast<size_t>(attributes[i+4]-attributes[i+3])));
44 } 50 }
51 auto* client = static_cast<XMLParser*>(parser)->getClient();
45 for (auto i = 0; i < nbNamespaces * 2; i += 2) { 52 for (auto i = 0; i < nbNamespaces * 2; i += 2) {
46 const auto prefix = namespaces[i] ? std::string(reinterpret_cast<const char*>(namespaces[i])) : ""; 53 const auto prefix = asString(namespaces[i]);
47 const auto uri = std::string(reinterpret_cast<const char*>(namespaces[i + 1])); 54 const auto uri = asString(namespaces[i + 1]);
48 static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(prefix, uri); 55 client->handleNamespaceDeclaration(prefix, uri);
49 } 56 }
50 static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); 57 auto nameStr = asString(name);
58 auto xmlsnsStr = asString(xmlns);
59 auto prefixStr = asString(prefix);
60 client->handleStartElementPrefix(prefixStr, xmlsnsStr, nameStr, nameStr, xmlsnsStr, attributeValues);
61 client->handleStartElement(nameStr, xmlsnsStr, attributeValues);
51} 62}
52 63
53static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) { 64static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) {
54 static_cast<XMLParser*>(parser)->getClient()->handleEndElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string())); 65 static_cast<XMLParser*>(parser)->getClient()->handleEndElement(asString(name), asString(xmlns));
55} 66}
56 67
57static void handleCharacterData(void* parser, const xmlChar* data, int len) { 68static void handleCharacterData(void* parser, const xmlChar* data, int len) {
diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp
index 4529eac..d9335c1 100644
--- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp
+++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp
@@ -15,6 +15,7 @@ class AttributeMapTest : public CppUnit::TestFixture
15{ 15{
16 CPPUNIT_TEST_SUITE(AttributeMapTest); 16 CPPUNIT_TEST_SUITE(AttributeMapTest);
17 CPPUNIT_TEST(testGetAttribute_Namespaced); 17 CPPUNIT_TEST(testGetAttribute_Namespaced);
18 CPPUNIT_TEST(testGetAttribute_Namespaced_Prefix);
18 CPPUNIT_TEST(testGetBoolAttribute_True); 19 CPPUNIT_TEST(testGetBoolAttribute_True);
19 CPPUNIT_TEST(testGetBoolAttribute_1); 20 CPPUNIT_TEST(testGetBoolAttribute_1);
20 CPPUNIT_TEST(testGetBoolAttribute_False); 21 CPPUNIT_TEST(testGetBoolAttribute_False);
@@ -34,6 +35,22 @@ class AttributeMapTest : public CppUnit::TestFixture
34 CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); 35 CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"));
35 } 36 }
36 37
38 void testGetAttribute_Namespaced_Prefix() {
39 AttributeMap testling;
40 testling.addAttribute("lang", "", "prefix", "nl");
41 testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "prefix", "en");
42 testling.addAttribute("lang", "", "prefix", "fr");
43
44 CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"));
45 const auto& entries = testling.getEntries();
46 auto it = std::find_if(entries.begin(), entries.end(), [](const AttributeMap::Entry& e) {
47 return e.getValue() == "en";
48 });
49 const bool found = it != entries.end();
50 CPPUNIT_ASSERT_EQUAL(true, found);
51 CPPUNIT_ASSERT_EQUAL(std::string("prefix"), it->getAttribute().getPrefix());
52 }
53
37 void testGetBoolAttribute_True() { 54 void testGetBoolAttribute_True() {
38 AttributeMap testling; 55 AttributeMap testling;
39 testling.addAttribute("foo", "", "true"); 56 testling.addAttribute("foo", "", "true");
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp
index 63d30ea..4db694e 100644
--- a/Swiften/Parser/UnitTest/XMLParserTest.cpp
+++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp
@@ -35,6 +35,7 @@ class XMLParserTest : public CppUnit::TestFixture {
35 CPPUNIT_TEST(testParse_WhitespaceInAttribute); 35 CPPUNIT_TEST(testParse_WhitespaceInAttribute);
36 CPPUNIT_TEST(testParse_AttributeWithoutNamespace); 36 CPPUNIT_TEST(testParse_AttributeWithoutNamespace);
37 CPPUNIT_TEST(testParse_AttributeWithNamespace); 37 CPPUNIT_TEST(testParse_AttributeWithNamespace);
38 CPPUNIT_TEST(testParse_AttributeWithNamespaceNoPrefix);
38 CPPUNIT_TEST(testParse_BillionLaughs); 39 CPPUNIT_TEST(testParse_BillionLaughs);
39 CPPUNIT_TEST(testParse_InternalEntity); 40 CPPUNIT_TEST(testParse_InternalEntity);
40 //CPPUNIT_TEST(testParse_UndefinedPrefix); 41 //CPPUNIT_TEST(testParse_UndefinedPrefix);
@@ -43,6 +44,7 @@ class XMLParserTest : public CppUnit::TestFixture {
43 CPPUNIT_TEST(testParse_DisallowCommentsInXML); 44 CPPUNIT_TEST(testParse_DisallowCommentsInXML);
44 CPPUNIT_TEST(testParse_Doctype); 45 CPPUNIT_TEST(testParse_Doctype);
45 CPPUNIT_TEST(testParse_ProcessingInstructions); 46 CPPUNIT_TEST(testParse_ProcessingInstructions);
47 CPPUNIT_TEST(testParse_ProcessingPrefixedElement);
46 CPPUNIT_TEST_SUITE_END(); 48 CPPUNIT_TEST_SUITE_END();
47 49
48 public: 50 public:
@@ -264,6 +266,7 @@ class XMLParserTest : public CppUnit::TestFixture {
264 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); 266 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());
265 CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); 267 CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());
266 CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); 268 CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace());
269 CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix());
267 } 270 }
268 271
269 void testParse_AttributeWithNamespace() { 272 void testParse_AttributeWithNamespace() {
@@ -275,6 +278,22 @@ class XMLParserTest : public CppUnit::TestFixture {
275 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); 278 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());
276 CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); 279 CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());
277 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); 280 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace());
281 CPPUNIT_ASSERT_EQUAL(std::string("f"), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix());
282 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size());
283 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]);
284 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]);
285 }
286
287 void testParse_AttributeWithNamespaceNoPrefix() {
288 ParserType testling(&client_);
289
290 CPPUNIT_ASSERT(testling.parse(
291 "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' attr='3'/>"));
292
293 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());
294 CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());
295 CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace());
296 CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix());
278 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); 297 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size());
279 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); 298 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]);
280 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); 299 CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]);
@@ -373,25 +392,52 @@ class XMLParserTest : public CppUnit::TestFixture {
373 CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); 392 CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>"));
374 } 393 }
375 394
395 void testParse_ProcessingPrefixedElement() {
396 client_.testingStartElementPrefix = true;
397 ParserType testling(&client_);
398
399 CPPUNIT_ASSERT(testling.parse("<prefix:message xmlns='uri' xmlns:prefix='uriPrefix'/>"));
400
401 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size());
402
403 CPPUNIT_ASSERT_EQUAL(Client::StartElementPrefix, client_.events[0].type);
404 CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data);
405 CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns);
406 CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix);
407
408 CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type);
409 CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data);
410 CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns);
411 }
412
376 private: 413 private:
377 class Client : public XMLParserClient { 414 class Client : public XMLParserClient {
378 public: 415 public:
379 using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; 416 using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>;
380 enum Type { StartElement, EndElement, CharacterData, NamespaceDefined }; 417 enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined };
381 struct Event { 418 struct Event {
382 Event( 419 Event(
383 Type type, 420 Type type,
384 const std::string& data, 421 const std::string& data,
385 const std::string& ns, 422 const std::string& ns,
423 const std::string& prefix,
424 const AttributeMap& attributes,
425 NamespaceMap namespaces)
426 : type(type), data(data), ns(ns), prefix(prefix), attributes(attributes), namespaces(std::move(namespaces)) {}
427 Event(
428 Type type,
429 const std::string& data,
430 const std::string& ns,
386 const AttributeMap& attributes, 431 const AttributeMap& attributes,
387 NamespaceMap namespaces = {}) 432 NamespaceMap namespaces = {})
388 : type(type), data(data), ns(ns), attributes(attributes), namespaces(std::move(namespaces)) {} 433 : Event(type, data, ns, {}, attributes, std::move(namespaces)) {}
389 Event(Type type, const std::string& data, const std::string& ns = std::string()) 434 Event(Type type, const std::string& data, const std::string& ns = std::string())
390 : type(type), data(data), ns(ns) {} 435 : Event(type, data, ns, "", AttributeMap(), NamespaceMap()) {}
391 436
392 Type type; 437 Type type;
393 std::string data; 438 std::string data;
394 std::string ns; 439 std::string ns;
440 std::string prefix;
395 AttributeMap attributes; 441 AttributeMap attributes;
396 NamespaceMap namespaces; 442 NamespaceMap namespaces;
397 }; 443 };
@@ -399,9 +445,15 @@ class XMLParserTest : public CppUnit::TestFixture {
399 Client() {} 445 Client() {}
400 446
401 void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { 447 void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override {
448 if (testingStartElementPrefix) return;
402 events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); 449 events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_)));
403 } 450 }
404 451
452 void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const std::string&, const std::string&, const AttributeMap&) override {
453 if (!testingStartElementPrefix) return;
454 events.push_back(Event(StartElementPrefix, name, uri, prefix, AttributeMap(), NamespaceMap()));
455 }
456
405 void handleEndElement(const std::string& element, const std::string& ns) override { 457 void handleEndElement(const std::string& element, const std::string& ns) override {
406 events.push_back(Event(EndElement, element, ns)); 458 events.push_back(Event(EndElement, element, ns));
407 } 459 }
@@ -415,6 +467,7 @@ class XMLParserTest : public CppUnit::TestFixture {
415 } 467 }
416 468
417 std::vector<Event> events; 469 std::vector<Event> events;
470 bool testingStartElementPrefix = false;
418 private: 471 private:
419 NamespaceMap namespaces_; 472 NamespaceMap namespaces_;
420 } client_; 473 } client_;
diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp
index 40be4e8..847e1f3 100644
--- a/Swiften/Parser/XMLParserClient.cpp
+++ b/Swiften/Parser/XMLParserClient.cpp
@@ -11,6 +11,12 @@ namespace Swift {
11XMLParserClient::~XMLParserClient() { 11XMLParserClient::~XMLParserClient() {
12} 12}
13 13
14void XMLParserClient::handleStartElement(const std::string&, const std::string&, const AttributeMap&) {
15}
16
17void XMLParserClient::handleStartElementPrefix(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const AttributeMap&) {
18}
19
14void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { 20void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) {
15} 21}
16 22
diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h
index 0682320..f519646 100644
--- a/Swiften/Parser/XMLParserClient.h
+++ b/Swiften/Parser/XMLParserClient.h
@@ -14,7 +14,13 @@ namespace Swift {
14 public: 14 public:
15 virtual ~XMLParserClient(); 15 virtual ~XMLParserClient();
16 16
17 virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; 17 /**
18 * Client will have to implement only one of the following methods depending on whether
19 * he is interested in processing the element prefix or not.
20 */
21 virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes);
22 virtual void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const std::string& element, const std::string& ns, const AttributeMap& attributes);
23
18 virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; 24 virtual void handleEndElement(const std::string& element, const std::string& ns) = 0;
19 virtual void handleCharacterData(const std::string& data) = 0; 25 virtual void handleCharacterData(const std::string& data) = 0;
20 26