src/XMLDocumentConstructor.h
branchv_0
changeset 31 c6527b45fbc2
parent 30 f686bdaeb9e0
child 32 e72546725c77
equal deleted inserted replaced
30:f686bdaeb9e0 31:c6527b45fbc2
    36 class HierarchicalINIContentHandler : public INIContentHandler {
    36 class HierarchicalINIContentHandler : public INIContentHandler {
    37 private:
    37 private:
    38 	xmlpp::DomParser* domParser;
    38 	xmlpp::DomParser* domParser;
    39 	XMLNameCodec nameCodec;
    39 	XMLNameCodec nameCodec;
    40 	xmlpp::Element* currentSection = nullptr;
    40 	xmlpp::Element* currentSection = nullptr;
       
    41 
       
    42 	enum class TreeStyle {
       
    43 		Standard,
       
    44 		Literal,
       
    45 	};
       
    46 
       
    47 	TreeStyle parseTreeStyle(const std::string& name) {
       
    48 		if (name == "standard") return TreeStyle::Standard;
       
    49 		else if (name == "literal") return TreeStyle::Literal;
       
    50 		else throw std::invalid_argument(std::string("Unknown tree style: ") + name);
       
    51 	}
       
    52 
       
    53 	TreeStyle treeStyle = TreeStyle::Literal;
       
    54 
       
    55 	/**
       
    56 	 * TODO: use a common method
       
    57 	 */
       
    58 	bool parseBoolean(const std::string& value) {
       
    59 		if (value == "true") return true;
       
    60 		else if (value == "false") return false;
       
    61 		else throw std::invalid_argument(std::string("Unable to parse boolean value: ") + value + " (expecting true or false)");
       
    62 	}
       
    63 
       
    64 	bool treeWithNamespaces = false;
       
    65 
    41 public:
    66 public:
    42 
    67 
    43 	HierarchicalINIContentHandler(xmlpp::DomParser* domParser) : domParser(domParser) {
    68 	HierarchicalINIContentHandler(xmlpp::DomParser* domParser) : domParser(domParser) {
    44 	}
    69 	}
    45 
    70 
    46 	virtual ~HierarchicalINIContentHandler() {
    71 	virtual ~HierarchicalINIContentHandler() {
    47 	}
    72 	}
    48 
    73 
    49 	void startDocument() override {
    74 	void startDocument() override {
    50 		if (currentSection) throw std::out_of_range("Lunatic INI parser send us multiple documents.");
    75 		if (currentSection) throw std::out_of_range("Lunatic INI parser send us multiple documents.");
    51 		currentSection = domParser->get_document()->create_root_node("ini");
    76 		currentSection = domParser->get_document()->create_root_node("ini", treeWithNamespaces ? xml::XMLNS : "");
    52 	};
    77 	};
    53 
    78 
    54 	void endDocument() override {
    79 	void endDocument() override {
    55 	};
    80 	};
    56 
    81 
    57 	void startSection(const SectionStartEvent& event) override {
    82 	void startSection(const SectionStartEvent& event) override {
    58 		currentSection = currentSection->add_child(nameCodec.encode(event.name));
    83 		currentSection = currentSection->add_child(treeStyle == TreeStyle::Literal ? nameCodec.encode(event.name) : "section");
    59 		currentSection->set_attribute("type", "section");
    84 		if (treeStyle == TreeStyle::Literal) currentSection->set_attribute("type", "section");
    60 		currentSection->set_attribute("name", event.name);
    85 		currentSection->set_attribute("name", event.name);
    61 		if (event.comment.size()) currentSection->set_attribute("comment", event.comment);
    86 		if (event.comment.size()) currentSection->set_attribute("comment", event.comment);
    62 		if (event.lineNumber >= 0) currentSection->set_attribute("line-number", std::to_string(event.lineNumber));
    87 		if (event.lineNumber >= 0) currentSection->set_attribute("line-number", std::to_string(event.lineNumber));
    63 		if (event.eventNumber >= 0) currentSection->set_attribute("event-number", std::to_string(event.eventNumber));
    88 		if (event.eventNumber >= 0) currentSection->set_attribute("event-number", std::to_string(event.eventNumber));
    64 	};
    89 	};
    67 		currentSection = currentSection->get_parent();
    92 		currentSection = currentSection->get_parent();
    68 		if (currentSection == nullptr) throw std::out_of_range("Lunatic INI parser tried to end a section without starting it before.");
    93 		if (currentSection == nullptr) throw std::out_of_range("Lunatic INI parser tried to end a section without starting it before.");
    69 	};
    94 	};
    70 
    95 
    71 	void entry(const EntryEvent& event) override {
    96 	void entry(const EntryEvent& event) override {
    72 		xmlpp::Element* entry = currentSection->add_child(nameCodec.encode(event.fullKey));
    97 		xmlpp::Element* entry = currentSection->add_child(treeStyle == TreeStyle::Literal ? nameCodec.encode(event.fullKey) : "entry");
    73 		entry->set_attribute("type", "entry");
    98 		if (treeStyle == TreeStyle::Literal) entry->set_attribute("type", "entry");
    74 		entry->set_attribute("key", event.key);
    99 		entry->set_attribute("key", event.key);
    75 		entry->set_attribute("full-key", event.fullKey);
   100 		entry->set_attribute("full-key", event.fullKey);
    76 		if (event.subKey.size()) entry->set_attribute("sub-key", event.subKey);
   101 		if (event.subKey.size()) entry->set_attribute("sub-key", event.subKey);
    77 		if (event.comment.size()) entry->set_attribute("comment", event.comment);
   102 		if (event.comment.size()) entry->set_attribute("comment", event.comment);
    78 		if (event.lineNumber >= 0) entry->set_attribute("line-number", std::to_string(event.lineNumber));
   103 		if (event.lineNumber >= 0) entry->set_attribute("line-number", std::to_string(event.lineNumber));
    80 		entry->add_child_text(event.value);
   105 		entry->add_child_text(event.value);
    81 	};
   106 	};
    82 
   107 
    83 	void comment(const CommentEvent& event) override {
   108 	void comment(const CommentEvent& event) override {
    84 		xmlpp::Element* comment = currentSection->add_child("comment");
   109 		xmlpp::Element* comment = currentSection->add_child("comment");
    85 		comment->set_attribute("type", "comment");
   110 		if (treeStyle == TreeStyle::Literal) comment->set_attribute("type", "comment");
    86 		if (event.lineNumber >= 0) comment->set_attribute("line-number", std::to_string(event.lineNumber));
   111 		if (event.lineNumber >= 0) comment->set_attribute("line-number", std::to_string(event.lineNumber));
    87 		if (event.eventNumber >= 0) comment->set_attribute("event-number", std::to_string(event.eventNumber));
   112 		if (event.eventNumber >= 0) comment->set_attribute("event-number", std::to_string(event.eventNumber));
    88 		comment->add_child_text(event.comment);
   113 		comment->add_child_text(event.comment);
    89 	}
   114 	}
    90 
   115 
    91 	void whitespace(const WhitespaceEvent& event) override {
   116 	void whitespace(const WhitespaceEvent& event) override {
    92 		xmlpp::Element* comment = currentSection->add_child("whitespace");
   117 		xmlpp::Element* whitespace = currentSection->add_child("whitespace");
    93 		comment->set_attribute("type", "whitespace");
   118 		if (treeStyle == TreeStyle::Literal) whitespace->set_attribute("type", "whitespace");
    94 		if (event.lineNumber >= 0) comment->set_attribute("line-number", std::to_string(event.lineNumber));
   119 		if (event.lineNumber >= 0) whitespace->set_attribute("line-number", std::to_string(event.lineNumber));
    95 		if (event.eventNumber >= 0) comment->set_attribute("event-number", std::to_string(event.eventNumber));
   120 		if (event.eventNumber >= 0) whitespace->set_attribute("event-number", std::to_string(event.eventNumber));
    96 		comment->add_child_text(event.whitespace);
   121 		whitespace->add_child_text(event.whitespace);
       
   122 	}
       
   123 
       
   124 	bool setOption(const std::string& uri, const std::string& value) {
       
   125 		if (uri == xml::TreeWithNamespaces) treeWithNamespaces = parseBoolean(value);
       
   126 		else if (uri == xml::TreeStyle) treeStyle = parseTreeStyle(value);
       
   127 		else return false;
       
   128 		return true;
    97 	}
   129 	}
    98 
   130 
    99 };
   131 };
   100 
   132 
   101 // TODO: support also other styles/mappings e.g. <section/> and <entry/> with INI names only in the XML attributes (and thus without @type="section|entry")
   133 // TODO: support also other styles/mappings e.g. <section/> and <entry/> with INI names only in the XML attributes (and thus without @type="section|entry")
   105 class XMLDocumentConstructor {
   137 class XMLDocumentConstructor {
   106 private:
   138 private:
   107 	std::istream* input = nullptr;
   139 	std::istream* input = nullptr;
   108 	xmlpp::DomParser* parser = nullptr;
   140 	xmlpp::DomParser* parser = nullptr;
   109 	std::shared_ptr<INIReader> reader;
   141 	std::shared_ptr<INIReader> reader;
       
   142 	std::shared_ptr<HierarchicalINIContentHandler> handler;
   110 public:
   143 public:
   111 
   144 
   112 	XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) {
   145 	XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) {
   113 		reader.reset(INIReader::create(*input));
   146 		reader.reset(INIReader::create(*input));
   114 		reader->addUnescapingProcessor(std::make_shared<BasicUnescapingProcessor>(), unescaping::Basic, true);
   147 		reader->addUnescapingProcessor(std::make_shared<BasicUnescapingProcessor>(), unescaping::Basic, true);
   115 		reader->addUnescapingProcessor(std::make_shared<JavaPropertiesUnescapingProcessor>(), unescaping::JavaProperties, false);
   148 		reader->addUnescapingProcessor(std::make_shared<JavaPropertiesUnescapingProcessor>(), unescaping::JavaProperties, false);
   116 		reader->addUnescapingProcessor(std::make_shared<BackspaceUnescapingProcessor>(), unescaping::Backspace, true);
   149 		reader->addUnescapingProcessor(std::make_shared<BackspaceUnescapingProcessor>(), unescaping::Backspace, true);
   117 		reader->addDialect(std::make_shared<JavaPropertiesDialect>(), dialect::JavaProperties, false);
   150 		reader->addDialect(std::make_shared<JavaPropertiesDialect>(), dialect::JavaProperties, false);
       
   151 		handler = std::make_shared<HierarchicalINIContentHandler>(parser);
   118 	}
   152 	}
   119 
   153 
   120 	void setOption(const std::string& uri, const std::string& value) {
   154 	void setOption(const std::string& uri, const std::string& value) {
       
   155 		if (handler->setOption(uri, value)) return;
   121 		reader->setOption(uri, value);
   156 		reader->setOption(uri, value);
   122 	}
   157 	}
   123 
   158 
   124 	void process() {
   159 	void process() {
   125 		HierarchicalINIContentHandler handler(parser);
   160 		reader->addHandler(handler.get());
   126 		reader->addHandler(&handler);
       
   127 		reader->process();
   161 		reader->process();
   128 	}
   162 	}
   129 };
   163 };
   130 
   164 
   131 }
   165 }