src/XMLTableCommand.h
branchv_0
changeset 8 8730e2d0db0e
parent 7 ff69af3c67a3
child 14 5be268bc4c69
--- a/src/XMLTableCommand.h	Thu Jan 02 23:31:44 2020 +0100
+++ b/src/XMLTableCommand.h	Sun Jan 05 01:01:12 2020 +0100
@@ -22,6 +22,8 @@
 #include <sstream>
 #include <vector>
 #include <algorithm>
+#include <exception>
+#include <regex>
 
 #include <libxml++-2.6/libxml++/libxml++.h>
 
@@ -39,6 +41,45 @@
 private:
 	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings.
 
+	string_t formatRawXML(string_t rawXML) {
+		std::wregex pattern(L"^<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>\n|\n$");
+		return std::regex_replace(rawXML, pattern, L"");
+	}
+
+	void importNode(xmlpp::Node* parent, xmlpp::Node* child, AttributeRecipe attributeRecipe) {
+		if (dynamic_cast<xmlpp::AttributeNode*> (child)) parent->add_child_with_new_ns(
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.name),
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.uri),
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.prefix))->import_node(child);
+		else parent->import_node(child, true);
+	}
+
+	void importNode(xmlpp::Document* document, xmlpp::Node* child, AttributeRecipe attributeRecipe) {
+		if (dynamic_cast<xmlpp::AttributeNode*> (child)) document->create_root_node(
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.name),
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.uri),
+				convertor.to_bytes(attributeRecipe.rawXmlAttributeWrapper.prefix))->import_node(child);
+		else document->create_root_node_by_import(child, true);
+	}
+
+	string_t toRawXML(xmlpp::Node* parent, AttributeRecipe attributeRecipe, xmlpp::Node::PrefixNsMap ns) {
+		xmlpp::Document d;
+		xmlpp::NodeSet nodes = parent->find(convertor.to_bytes(attributeRecipe.xpath), ns);
+
+		if (attributeRecipe.rawXmlNodeListWrapper.name.size()) {
+			d.create_root_node(
+					convertor.to_bytes(attributeRecipe.rawXmlNodeListWrapper.name),
+					convertor.to_bytes(attributeRecipe.rawXmlNodeListWrapper.uri),
+					convertor.to_bytes(attributeRecipe.rawXmlNodeListWrapper.prefix));
+			for (xmlpp::Node* node : nodes) importNode(d.get_root_node(), node, attributeRecipe);
+		} else {
+			if (nodes.size() == 1) importNode(&d, nodes[0], attributeRecipe);
+			else if (nodes.size() > 1) throw std::invalid_argument("Multiple nodes found where only one was expected. Use nodelist wrapper."); // TODO: better relpipe exception
+			else return L""; // TODO: null
+		}
+		return formatRawXML(convertor.from_bytes(d.write_to_string()));
+	}
+
 public:
 
 	void process(std::istream& input, std::ostream& output, Configuration& configuration) {
@@ -64,7 +105,24 @@
 			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)));
+					std::string attributeXpath = convertor.to_bytes(a.xpath);
+					if (a.mode == Mode::STRING) {
+						writer->writeAttribute(convertor.from_bytes(n->eval_to_string(attributeXpath, ns)));
+					} else if (a.mode == Mode::BOOLEAN) {
+						writer->writeAttribute(n->eval_to_boolean(attributeXpath, ns) ? L"true" : L"false");
+					} else if (a.mode == Mode::LINE_NUMBER) {
+						xmlpp::NodeSet attributeNodes = n->find(attributeXpath, ns);
+						string_t line = attributeNodes.size() ? std::to_wstring(attributeNodes[0]->get_line()) : L""; // TODO: null
+						writer->writeAttribute(line);
+					} else if (a.mode == Mode::XPATH) {
+						xmlpp::NodeSet attributeNodes = n->find(attributeXpath, ns);
+						string_t line = attributeNodes.size() ? convertor.from_bytes(attributeNodes[0]->get_path()) : L""; // TODO: null
+						writer->writeAttribute(line);
+					} else if (a.mode == Mode::RAW_XML) {
+						writer->writeAttribute(toRawXML(n, a, ns));
+					} else {
+						throw logic_error("Unsupported mode."); // should never happer, TODO: better relpipe exception
+					}
 				}
 			}
 		}