convert arbitrary XML to one or more relations v_0 v0.13
authorFrantišek Kučera <franta-hg@frantovo.cz>
Wed, 24 Jul 2019 21:29:56 +0200
branchv_0
changeset 2 0d3eb5129582
parent 1 7d6ac51c0d48
child 3 535a232e6014
convert arbitrary XML to one or more relations
src/CLIParser.h
src/Configuration.h
src/XMLTableCommand.h
src/relpipe-in-xmltable.cpp
--- a/src/CLIParser.h	Wed Jul 24 15:53:42 2019 +0200
+++ b/src/CLIParser.h	Wed Jul 24 21:29:56 2019 +0200
@@ -56,6 +56,7 @@
 
 	static const string_t OPTION_NAMESPACE;
 	static const string_t OPTION_RELATION;
+	static const string_t OPTION_NAME_IS_XPATH;
 	static const string_t OPTION_RECORDS;
 	static const string_t OPTION_ATTRIBUTE;
 
@@ -72,6 +73,8 @@
 			} else if (option == OPTION_RELATION) {
 				addRelation(c, currentRelation); // previous relation
 				currentRelation.relation = readNext(arguments, i);
+			} else if (option == OPTION_NAME_IS_XPATH) {
+				currentRelation.nameIsXPath = true;
 			} else if (option == OPTION_RECORDS) {
 				currentRelation.xpath = readNext(arguments, i);
 			} else if (option == OPTION_ATTRIBUTE) {
@@ -93,6 +96,7 @@
 
 const string_t CLIParser::OPTION_NAMESPACE = L"--namespace";
 const string_t CLIParser::OPTION_RELATION = L"--relation";
+const string_t CLIParser::OPTION_NAME_IS_XPATH = L"--name-is-xpath";
 const string_t CLIParser::OPTION_RECORDS = L"--records";
 const string_t CLIParser::OPTION_ATTRIBUTE = L"--attribute";
 
--- a/src/Configuration.h	Wed Jul 24 15:53:42 2019 +0200
+++ b/src/Configuration.h	Wed Jul 24 21:29:56 2019 +0200
@@ -44,6 +44,7 @@
 	}
 
 	relpipe::writer::string_t relation;
+	relpipe::writer::boolean_t nameIsXPath = false;
 	relpipe::writer::string_t xpath;
 	std::vector<AttributeRecipe> attributes;
 	
--- a/src/XMLTableCommand.h	Wed Jul 24 15:53:42 2019 +0200
+++ b/src/XMLTableCommand.h	Wed Jul 24 21:29:56 2019 +0200
@@ -28,6 +28,7 @@
 
 #include <relpipe/writer/typedefs.h>
 
+#include "Configuration.h"
 
 namespace relpipe {
 namespace in {
@@ -37,29 +38,36 @@
 
 class XMLCommand {
 private:
+	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings.
 
 public:
 
-	void process(std::istream& input, std::ostream& output) {
-
+	void process(std::istream& input, std::ostream& output, Configuration& configuration) {
+		std::shared_ptr<RelationalWriter> writer(Factory::create(output));
 
 		xmlpp::DomParser parser;
 		parser.parse_stream(input);
-		xmlpp::Document* d = parser.get_document();
-		xmlpp::Element* r = d->get_root_node();
-
-		xmlpp::Node::PrefixNsMap m;
-		m["rp"] = "tag:globalcode.info,2018:relpipe";
+		xmlpp::Element* root = parser.get_document()->get_root_node();
 
-		output << "root: " << r->get_name() << std::endl;
-
-		for (xmlpp::Node* n : r->find("//rp:attribute", m)) {
-
-			output << "node:" << n->get_name() << std::endl;
-
+		xmlpp::Node::PrefixNsMap ns;
+		for (int i = 0; i < configuration.namespaceMappings.size(); i++) {
+			std::string prefix = convertor.to_bytes(configuration.namespaceMappings[i]);
+			std::string uri = convertor.to_bytes(configuration.namespaceMappings[++i]);
+			ns[prefix] = uri;
 		}
 
-
+		for (const RelationConfiguration& r : configuration.relationConfigurations) {
+			std::vector<relpipe::writer::AttributeMetadata> attributesMetadata;
+			for (AttributeRecipe a : r.attributes) attributesMetadata.push_back(AttributeMetadata{a.name, a.type});
+			relpipe::writer::string_t name = r.nameIsXPath ? convertor.from_bytes(root->eval_to_string(convertor.to_bytes(r.relation), ns)) : r.relation;
+			writer->startRelation(name, attributesMetadata, true);
+			for (xmlpp::Node* n : root->find(convertor.to_bytes(r.xpath), ns)) {
+				for (AttributeRecipe a : r.attributes) {
+					// TODO: convert to bytes only once
+					writer->writeAttribute(convertor.from_bytes(n->eval_to_string(convertor.to_bytes(a.xpath), ns)));
+				}
+			}
+		}
 	}
 };
 
--- a/src/relpipe-in-xmltable.cpp	Wed Jul 24 15:53:42 2019 +0200
+++ b/src/relpipe-in-xmltable.cpp	Wed Jul 24 21:29:56 2019 +0200
@@ -50,7 +50,7 @@
 		CLIParser cliParser;
 		Configuration configuration = cliParser.parse(cli.arguments());
 		XMLCommand command;
-		command.process(cin, cout);
+		command.process(cin, cout, configuration);
 		resultCode = CLI::EXIT_CODE_SUCCESS;
 	} catch (RelpipeWriterException& e) {
 		fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str());