diff options
author | Tim Robbings <tim.robbings@isode.com> | 2015-01-26 17:33:20 (GMT) |
---|---|---|
committer | Kevin Smith <kevin.smith@isode.com> | 2015-02-17 12:17:35 (GMT) |
commit | 55461d1b5f97591b4ab9510896ca1bc5b5e2a71f (patch) | |
tree | 17c79419d06c6740bb6ff04f6e17a13e7c4533a5 /Swiften/Parser/PayloadParsers | |
parent | 265b779d6766130afa8f2f166733dc172ba22dca (diff) | |
download | swift-55461d1b5f97591b4ab9510896ca1bc5b5e2a71f.zip swift-55461d1b5f97591b4ab9510896ca1bc5b5e2a71f.tar.bz2 |
Swiften XEP-0141 support
Classes to support XEP-0141 data forms layout. This includes <page/>,
<section/>, <reportedref/> and <text/> elements. The form
parser and serializer classes have also been updated to handle these new
elements, with added CPPUnit tests.
Test-information:
Tested using updated CPPUnit tests to check the parsing and serializing of
new elements. All tests complete successfully.
Change-Id: Ibeab22d2834512d06c7f656acd1ef24eea39d650
Diffstat (limited to 'Swiften/Parser/PayloadParsers')
-rw-r--r-- | Swiften/Parser/PayloadParsers/FormParser.cpp | 94 | ||||
-rw-r--r-- | Swiften/Parser/PayloadParsers/FormParser.h | 12 | ||||
-rw-r--r-- | Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp | 46 |
3 files changed, 145 insertions, 7 deletions
diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp index 7422c7b..d400c4c 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.cpp +++ b/Swiften/Parser/PayloadParsers/FormParser.cpp @@ -1,20 +1,21 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ - +#include <iostream> #include <Swiften/Parser/PayloadParsers/FormParser.h> - +#include <map> #include <Swiften/Base/foreach.h> namespace Swift { -FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false), parsingOption_(false) { +FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false), parsingOption_(false), parseStarted_(false), hasReportedRef_(false){ } void FormParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { if (level_ == TopLevel) { + parseStarted_ = true; std::string type = attributes.getAttribute("type"); if (type == "form") { getPayloadInternal()->setType(Form::FormType); @@ -42,6 +43,10 @@ void FormParser::handleStartElement(const std::string& element, const std::strin else if (element == "item") { parsingItem_ = true; } + else if (element == "page") { + currentPage_ = boost::make_shared<FormPage>(); + currentPage_->setLabel(attributes.getAttribute("label")); + } } else if (level_ == FieldLevel && currentField_) { currentText_.clear(); @@ -94,6 +99,30 @@ void FormParser::handleStartElement(const std::string& element, const std::strin currentText_.clear(); } } + if (level_ > PayloadLevel) { + if (element == "section") { + currentSection_ = boost::make_shared<FormSection>(); + currentSection_->setLabel(attributes.getAttribute("label")); + sectionStack_.push_back(currentSection_); + currentSections_.push_back(currentSection_); + } + if (element == "reportedref") { + currentReportedRef_ = boost::make_shared<FormReportedRef>(); + } + if (element == "fieldref") { + currentText_.clear(); + currentFieldRef_ = attributes.getAttribute("var"); + if (sectionStack_.size() > 0) { + sectionStack_.at(sectionStack_.size()-1)->addFieldRef(currentFieldRef_); + } else if (currentPage_) { + currentPage_->addFieldRef(currentFieldRef_); + } + } + if (element == "text") { + currentText_.clear(); + currentTextElement_ = boost::make_shared<FormText>(); + } + } ++level_; } @@ -126,6 +155,10 @@ void FormParser::handleEndElement(const std::string& element, const std::string& getPayloadInternal()->addItem(currentFields_); currentFields_.clear(); } + else if (element == "page") { + getPayloadInternal()->addPage(currentPage_); + currentPages_.push_back(currentPage_); + } } else if (currentField_) { if (element == "required") { @@ -156,11 +189,62 @@ void FormParser::handleEndElement(const std::string& element, const std::string& currentFields_.push_back(currentField_); } else { - getPayloadInternal()->addField(currentField_); + if (currentPages_.size() > 0) { + foreach (boost::shared_ptr<FormPage> page, currentPages_) { + foreach (std::string pRef, page->getFieldRefs()) { + if (pRef == currentField_->getName()) { + page->addField(currentField_); + } + } + } + foreach (boost::shared_ptr<FormSection> section, currentSections_) { + foreach (std::string sRef, section->getFieldRefs()) { + if (sRef == currentField_->getName()) { + section->addField(currentField_); + } + } + } + } else { + getPayloadInternal()->addField(currentField_); + } } currentField_.reset(); } } + if (level_ > PayloadLevel) { + if (element == "section") { + if (sectionStack_.size() > 1) { + // Add the section at the top of the stack to the level below + sectionStack_.at(sectionStack_.size()-2)->addChildSection(sectionStack_.at(sectionStack_.size()-1)); + sectionStack_.pop_back(); + } + else if (sectionStack_.size() == 1) { + // Add the remaining section on the stack to it's parent page + currentPage_->addChildSection(sectionStack_.at(sectionStack_.size()-1)); + sectionStack_.pop_back(); + } + } + if (currentReportedRef_ && !hasReportedRef_) { + if (sectionStack_.size() > 0) { + sectionStack_.at(sectionStack_.size()-1)->addReportedRef(currentReportedRef_); + } else if (currentPage_) { + currentPage_->addReportedRef(currentReportedRef_); + } + hasReportedRef_ = true; + currentReportedRef_.reset(); + } + if (currentTextElement_) { + if (element == "text") { + currentTextElement_->setTextString(currentText_); + } + if (sectionStack_.size() > 0) { + sectionStack_.at(sectionStack_.size()-1)->addTextElement(currentTextElement_); + } else if (currentPage_) { + currentPage_->addTextElement(currentTextElement_); + } + currentTextElement_.reset(); + } + } } void FormParser::handleCharacterData(const std::string& text) { diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h index 85210a5..f865a38 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.h +++ b/Swiften/Parser/PayloadParsers/FormParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -27,10 +27,20 @@ namespace Swift { std::string currentText_; std::string currentOptionLabel_; std::string currentOptionValue_; + std::string currentFieldRef_; bool parsingItem_; bool parsingReported_; bool parsingOption_; + bool parseStarted_; + bool hasReportedRef_; FormField::ref currentField_; std::vector<FormField::ref> currentFields_; + FormText::text currentTextElement_; + FormReportedRef::ref currentReportedRef_; + FormPage::page currentPage_; + FormSection::section currentSection_; + std::vector<boost::shared_ptr<FormPage> > currentPages_; + std::vector<boost::shared_ptr<FormSection> > sectionStack_; + std::vector<boost::shared_ptr<FormSection> > currentSections_; }; } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp index 83fca83..c9e685e 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,6 +15,7 @@ using namespace Swift; class FormParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(FormParserTest); CPPUNIT_TEST(testParse_FormInformation); + CPPUNIT_TEST(testParse_FormLayout); CPPUNIT_TEST(testParse); CPPUNIT_TEST(testParse_FormItems); CPPUNIT_TEST_SUITE_END(); @@ -37,6 +38,49 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Form::SubmitType, payload->getType()); } + void testParse_FormLayout() { + PayloadsParserTester parser; + + // P1 = page one, S1 = section one, F1 = field one, T1 = text one + CPPUNIT_ASSERT(parser.parse( + "<x type=\"form\" xmlns=\"jabber:x:data\">" + "<page label=\"P1\" xmlns=\"http://jabber.org/protocol/xdata-layout\">" + "<reportedref/>" + "<text>P1T1</text>" + "<fieldref var=\"P1F1\"/>" + "<section label=\"P1S1\">" + "<text>P1S1T1</text>" + "<fieldref var=\"P1S1F1\"/>" + "</section>" + "</page>" + "<page label=\"P2\" xmlns=\"http://jabber.org/protocol/xdata-layout\">" + "<section label=\"P2S1\">" + "<section label=\"P2S2\">" + "<section label=\"P2S3\"/>" + "</section>" + "</section>" + "</page>" + "<field label=\"field one\" type=\"text-single\" var=\"P1F1\"/>" + "<field label=\"field two\" type=\"text-single\" var=\"P1S1F1\"/>" + "</x>")); + + Form* payload = dynamic_cast<Form*>(parser.getPayload().get()); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(payload->getFields().size())); + // PAGE ONE - parsing of element types + CPPUNIT_ASSERT_EQUAL(std::string("P1"), payload->getPages()[0]->getLabel()); + CPPUNIT_ASSERT(payload->getPages()[0]->getReportedRefs()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("P1T1"), payload->getPages()[0]->getTextElements()[0]->getTextString()); + CPPUNIT_ASSERT_EQUAL(std::string("P1F1"), payload->getPages()[0]->getFields()[0]->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("P1S1"), payload->getPages()[0]->getChildSections()[0]->getLabel()); + CPPUNIT_ASSERT_EQUAL(std::string("P1S1T1"), payload->getPages()[0]->getChildSections()[0]->getTextElements()[0]->getTextString()); + CPPUNIT_ASSERT_EQUAL(std::string("P1S1F1"), payload->getPages()[0]->getChildSections()[0]->getFields()[0]->getName()); + // PAGE TWO - parsing of nested elements + CPPUNIT_ASSERT_EQUAL(std::string("P2"), payload->getPages()[1]->getLabel()); + CPPUNIT_ASSERT_EQUAL(std::string("P2S1"), payload->getPages()[1]->getChildSections()[0]->getLabel()); + CPPUNIT_ASSERT_EQUAL(std::string("P2S2"), payload->getPages()[1]->getChildSections()[0]->getChildSections()[0]->getLabel()); + CPPUNIT_ASSERT_EQUAL(std::string("P2S3"), payload->getPages()[1]->getChildSections()[0]->getChildSections()[0]->getChildSections()[0]->getLabel()); + } + void testParse() { PayloadsParserTester parser; |