add --parser-option tree-style standard|literal --parser-option tree-with-namespaces true|false v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 29 Nov 2020 10:49:33 +0100
branchv_0
changeset 31 c6527b45fbc2
parent 30 f686bdaeb9e0
child 32 e72546725c77
add --parser-option tree-style standard|literal --parser-option tree-with-namespaces true|false
bash-completion.sh
src/XMLDocumentConstructor.h
src/lib/uri.h
--- a/bash-completion.sh	Sun Nov 29 00:30:36 2020 +0100
+++ b/bash-completion.sh	Sun Nov 29 10:49:33 2020 +0100
@@ -73,12 +73,19 @@
 		"unescape-basic"
 		"unescape-java-properties"
 		"unescape-backspace"
+		"tree-style"
+		"tree-with-namespaces"
 	);
 
 	DIALECTS=(
 		"java-properties"
 	);
 
+	TREE_STYLES=(
+		"standard"
+		"literal"
+	)
+
 
 	if   [[ "$w1" == "--relation"                      && "x$w0" == "x" ]];    then COMPREPLY=("''")
 	elif [[ "$w1" == "--records"                       && "x$w0" == "x" ]];    then COMPREPLY=("'/'")
@@ -109,6 +116,8 @@
 	elif [[ "$w2" == "--parser-option" && "$w1" == "comment-separators"      && "x$w0" == "x" ]];    then COMPREPLY=("'#;'")
 	elif [[ "$w2" == "--parser-option" && "$w1" == "key-value-separators"    && "x$w0" == "x" ]];    then COMPREPLY=("'=:'")
 	elif [[ "$w2" == "--parser-option" && "$w1" == "quotes"                  && "x$w0" == "x" ]];    then COMPREPLY=("\$'\"\\''")
+	elif [[ "$w2" == "--parser-option" && "$w1" == "tree-style"                               ]];    then COMPREPLY=($(compgen -W "${TREE_STYLES[*]}" -- "$w0"))
+	elif [[ "$w2" == "--parser-option" && "$w1" == "tree-with-namespaces"                     ]];    then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
 
 	else
 		OPTIONS=(
--- a/src/XMLDocumentConstructor.h	Sun Nov 29 00:30:36 2020 +0100
+++ b/src/XMLDocumentConstructor.h	Sun Nov 29 10:49:33 2020 +0100
@@ -38,6 +38,31 @@
 	xmlpp::DomParser* domParser;
 	XMLNameCodec nameCodec;
 	xmlpp::Element* currentSection = nullptr;
+
+	enum class TreeStyle {
+		Standard,
+		Literal,
+	};
+
+	TreeStyle parseTreeStyle(const std::string& name) {
+		if (name == "standard") return TreeStyle::Standard;
+		else if (name == "literal") return TreeStyle::Literal;
+		else throw std::invalid_argument(std::string("Unknown tree style: ") + name);
+	}
+
+	TreeStyle treeStyle = TreeStyle::Literal;
+
+	/**
+	 * TODO: use a common method
+	 */
+	bool parseBoolean(const std::string& value) {
+		if (value == "true") return true;
+		else if (value == "false") return false;
+		else throw std::invalid_argument(std::string("Unable to parse boolean value: ") + value + " (expecting true or false)");
+	}
+
+	bool treeWithNamespaces = false;
+
 public:
 
 	HierarchicalINIContentHandler(xmlpp::DomParser* domParser) : domParser(domParser) {
@@ -48,15 +73,15 @@
 
 	void startDocument() override {
 		if (currentSection) throw std::out_of_range("Lunatic INI parser send us multiple documents.");
-		currentSection = domParser->get_document()->create_root_node("ini");
+		currentSection = domParser->get_document()->create_root_node("ini", treeWithNamespaces ? xml::XMLNS : "");
 	};
 
 	void endDocument() override {
 	};
 
 	void startSection(const SectionStartEvent& event) override {
-		currentSection = currentSection->add_child(nameCodec.encode(event.name));
-		currentSection->set_attribute("type", "section");
+		currentSection = currentSection->add_child(treeStyle == TreeStyle::Literal ? nameCodec.encode(event.name) : "section");
+		if (treeStyle == TreeStyle::Literal) currentSection->set_attribute("type", "section");
 		currentSection->set_attribute("name", event.name);
 		if (event.comment.size()) currentSection->set_attribute("comment", event.comment);
 		if (event.lineNumber >= 0) currentSection->set_attribute("line-number", std::to_string(event.lineNumber));
@@ -69,8 +94,8 @@
 	};
 
 	void entry(const EntryEvent& event) override {
-		xmlpp::Element* entry = currentSection->add_child(nameCodec.encode(event.fullKey));
-		entry->set_attribute("type", "entry");
+		xmlpp::Element* entry = currentSection->add_child(treeStyle == TreeStyle::Literal ? nameCodec.encode(event.fullKey) : "entry");
+		if (treeStyle == TreeStyle::Literal) entry->set_attribute("type", "entry");
 		entry->set_attribute("key", event.key);
 		entry->set_attribute("full-key", event.fullKey);
 		if (event.subKey.size()) entry->set_attribute("sub-key", event.subKey);
@@ -82,18 +107,25 @@
 
 	void comment(const CommentEvent& event) override {
 		xmlpp::Element* comment = currentSection->add_child("comment");
-		comment->set_attribute("type", "comment");
+		if (treeStyle == TreeStyle::Literal) comment->set_attribute("type", "comment");
 		if (event.lineNumber >= 0) comment->set_attribute("line-number", std::to_string(event.lineNumber));
 		if (event.eventNumber >= 0) comment->set_attribute("event-number", std::to_string(event.eventNumber));
 		comment->add_child_text(event.comment);
 	}
 
 	void whitespace(const WhitespaceEvent& event) override {
-		xmlpp::Element* comment = currentSection->add_child("whitespace");
-		comment->set_attribute("type", "whitespace");
-		if (event.lineNumber >= 0) comment->set_attribute("line-number", std::to_string(event.lineNumber));
-		if (event.eventNumber >= 0) comment->set_attribute("event-number", std::to_string(event.eventNumber));
-		comment->add_child_text(event.whitespace);
+		xmlpp::Element* whitespace = currentSection->add_child("whitespace");
+		if (treeStyle == TreeStyle::Literal) whitespace->set_attribute("type", "whitespace");
+		if (event.lineNumber >= 0) whitespace->set_attribute("line-number", std::to_string(event.lineNumber));
+		if (event.eventNumber >= 0) whitespace->set_attribute("event-number", std::to_string(event.eventNumber));
+		whitespace->add_child_text(event.whitespace);
+	}
+
+	bool setOption(const std::string& uri, const std::string& value) {
+		if (uri == xml::TreeWithNamespaces) treeWithNamespaces = parseBoolean(value);
+		else if (uri == xml::TreeStyle) treeStyle = parseTreeStyle(value);
+		else return false;
+		return true;
 	}
 
 };
@@ -107,6 +139,7 @@
 	std::istream* input = nullptr;
 	xmlpp::DomParser* parser = nullptr;
 	std::shared_ptr<INIReader> reader;
+	std::shared_ptr<HierarchicalINIContentHandler> handler;
 public:
 
 	XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) {
@@ -115,15 +148,16 @@
 		reader->addUnescapingProcessor(std::make_shared<JavaPropertiesUnescapingProcessor>(), unescaping::JavaProperties, false);
 		reader->addUnescapingProcessor(std::make_shared<BackspaceUnescapingProcessor>(), unescaping::Backspace, true);
 		reader->addDialect(std::make_shared<JavaPropertiesDialect>(), dialect::JavaProperties, false);
+		handler = std::make_shared<HierarchicalINIContentHandler>(parser);
 	}
 
 	void setOption(const std::string& uri, const std::string& value) {
+		if (handler->setOption(uri, value)) return;
 		reader->setOption(uri, value);
 	}
 
 	void process() {
-		HierarchicalINIContentHandler handler(parser);
-		reader->addHandler(&handler);
+		reader->addHandler(handler.get());
 		reader->process();
 	}
 };
--- a/src/lib/uri.h	Sun Nov 29 00:30:36 2020 +0100
+++ b/src/lib/uri.h	Sun Nov 29 10:49:33 2020 +0100
@@ -44,6 +44,13 @@
 static const char* JavaProperties = "java-properties";
 }
 
+namespace xml {
+static const char* TreeWithNamespaces = "tree-with-namespaces";
+static const char* TreeStyle = "tree-style";
+
+static const char* XMLNS = "tag:globalcode.info,2018:alt2xml:TEMPORARY:ini"; // not an option and might change, just preliminary namespace
+}
+
 }
 }
 }