--- 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
+ }
}
}
}