src/XPathHandler.h
branchv_0
changeset 2 426054465916
parent 1 d6dbd5d50d43
child 3 709abeb5f6d1
equal deleted inserted replaced
1:d6dbd5d50d43 2:426054465916
    32 #include <relpipe/writer/Factory.h>
    32 #include <relpipe/writer/Factory.h>
    33 
    33 
    34 #include <relpipe/cli/RelpipeCLIException.h>
    34 #include <relpipe/cli/RelpipeCLIException.h>
    35 
    35 
    36 #include "Configuration.h"
    36 #include "Configuration.h"
       
    37 #include "XMLNameCodec.h"
    37 
    38 
    38 namespace relpipe {
    39 namespace relpipe {
    39 namespace tr {
    40 namespace tr {
    40 namespace xpath {
    41 namespace xpath {
    41 
    42 
    42 class XPathHandler : public relpipe::reader::handlers::RelationalReaderStringHandler {
    43 class XPathHandler : public relpipe::reader::handlers::RelationalReaderStringHandler {
    43 private:
    44 private:
       
    45 	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML is in UTF-8
    44 	shared_ptr<relpipe::writer::RelationalWriter> relationalWriter;
    46 	shared_ptr<relpipe::writer::RelationalWriter> relationalWriter;
    45 	Configuration configuration;
    47 	Configuration configuration;
    46 	RelationConfiguration* currentRelationConfiguration;
    48 	RelationConfiguration* currentRelationConfiguration = nullptr;
    47 	std::vector<relpipe::reader::handlers::AttributeMetadata> currentReaderMetadata;
    49 	std::vector<relpipe::reader::handlers::AttributeMetadata> currentReaderMetadata;
    48 	std::vector<relpipe::writer::AttributeMetadata> currentWriterMetadata;
    50 	std::vector<relpipe::writer::AttributeMetadata> currentWriterMetadata;
    49 	size_t currentAttributeIndex = 0;
    51 	size_t currentAttributeIndex = 0;
    50 	
    52 
       
    53 
    51 	xmlpp::DomParser dom;
    54 	xmlpp::DomParser dom;
       
    55 	xmlpp::Element* recordElement = nullptr;
       
    56 	relpipe::in::xmltable::XMLNameCodec xmlNameCodec; // TODO: move to a common library
    52 
    57 
    53 	void copyInputAttributesToOutput() {
    58 	void copyInputAttributesToOutput() {
    54 		for (auto rm : currentReaderMetadata) currentWriterMetadata.push_back({rm.getAttributeName(), relationalWriter->toTypeId(rm.getTypeName())});
    59 		for (auto rm : currentReaderMetadata) currentWriterMetadata.push_back({rm.getAttributeName(), relationalWriter->toTypeId(rm.getTypeName())});
    55 	}
    60 	}
    56 
    61 
    59 				|| (currentRelationConfiguration->inputAttributePolicy == InputAttributePolicy::Auto && currentRelationConfiguration->outputAttributes.size() == 0);
    64 				|| (currentRelationConfiguration->inputAttributePolicy == InputAttributePolicy::Auto && currentRelationConfiguration->outputAttributes.size() == 0);
    60 	}
    65 	}
    61 
    66 
    62 	bool isAppendingInputAttributes() {
    67 	bool isAppendingInputAttributes() {
    63 		return currentRelationConfiguration->inputAttributePolicy == InputAttributePolicy::Append;
    68 		return currentRelationConfiguration->inputAttributePolicy == InputAttributePolicy::Append;
       
    69 	}
       
    70 
       
    71 	void resetRecordElement() {
       
    72 		if (recordElement) dom.get_document()->get_root_node()->remove_child(recordElement);
       
    73 		recordElement = dom.get_document()->get_root_node()->add_child("record");
       
    74 	}
       
    75 
       
    76 	const Glib::ustring s2x(relpipe::common::type::StringX value) {
       
    77 		return Glib::ustring(convertor.to_bytes(value));
       
    78 	}
       
    79 
       
    80 	const relpipe::common::type::StringX x2s(const Glib::ustring& value) {
       
    81 		return convertor.from_bytes(value);
       
    82 	}
       
    83 
       
    84 	void writeInputAttributes() {
       
    85 		for (xmlpp::Node* attributeNode : recordElement->get_children()) {
       
    86 			if (xmlpp::Element * attributeElement = dynamic_cast<xmlpp::Element*> (attributeNode)) {
       
    87 				auto value = attributeElement->get_child_text()->get_content();
       
    88 				relationalWriter->writeAttribute(x2s(value));
       
    89 			}
       
    90 		}
       
    91 	}
       
    92 
       
    93 	void writeOutputAttributes() {
       
    94 		for (auto oa : currentRelationConfiguration->outputAttributes) {
       
    95 			auto value = recordElement->eval_to_string(s2x(oa.xpath));
       
    96 			relationalWriter->writeAttribute(x2s(value));
       
    97 		}
    64 	}
    98 	}
    65 
    99 
    66 public:
   100 public:
    67 
   101 
    68 	XPathHandler(shared_ptr<relpipe::writer::RelationalWriter> relationalWriter, Configuration configuration) : relationalWriter(relationalWriter), configuration(configuration) {
   102 	XPathHandler(shared_ptr<relpipe::writer::RelationalWriter> relationalWriter, Configuration configuration) : relationalWriter(relationalWriter), configuration(configuration) {
    90 			if (isPrependingInputAttributes()) copyInputAttributesToOutput();
   124 			if (isPrependingInputAttributes()) copyInputAttributesToOutput();
    91 			for (auto oa : currentRelationConfiguration->outputAttributes) currentWriterMetadata.push_back({oa.name, oa.type});
   125 			for (auto oa : currentRelationConfiguration->outputAttributes) currentWriterMetadata.push_back({oa.name, oa.type});
    92 			if (isAppendingInputAttributes()) copyInputAttributesToOutput();
   126 			if (isAppendingInputAttributes()) copyInputAttributesToOutput();
    93 
   127 
    94 			// TODO: prepare DOM
   128 			// TODO: prepare DOM
       
   129 			dom.get_document()->create_root_node("relpipe-tr-xpath");
       
   130 			resetRecordElement();
    95 		}
   131 		}
    96 
   132 
    97 		relationalWriter->startRelation(name, currentWriterMetadata, true);
   133 		relationalWriter->startRelation(name, currentWriterMetadata, true);
    98 	}
   134 	}
    99 
   135 
   100 	void attribute(const relpipe::common::type::StringX& value) override {
   136 	void attribute(const relpipe::common::type::StringX& value) override {
   101 		if (currentRelationConfiguration) {
   137 		if (currentRelationConfiguration) {
   102 			relpipe::reader::handlers::AttributeMetadata attributeMetadata = currentReaderMetadata[currentAttributeIndex];
   138 			relpipe::reader::handlers::AttributeMetadata attributeMetadata = currentReaderMetadata[currentAttributeIndex];
   103 
   139 
   104 			// TODO: add attribute to DOM		
   140 			xmlpp::Element* attributeElement = recordElement->add_child(xmlNameCodec.encode(s2x(attributeMetadata.getAttributeName())));
       
   141 			attributeElement->set_attribute("name", s2x(attributeMetadata.getAttributeName()));
       
   142 			attributeElement->set_attribute("type", s2x(attributeMetadata.getTypeName()));
       
   143 			attributeElement->add_child_text(s2x(value));
   105 
   144 
   106 			currentAttributeIndex++;
   145 			currentAttributeIndex++;
   107 
   146 
   108 			if (currentAttributeIndex == currentReaderMetadata.size()) {
   147 			if (currentAttributeIndex == currentReaderMetadata.size()) {
       
   148 				if (currentRelationConfiguration->where.empty() || recordElement->eval_to_boolean(s2x(currentRelationConfiguration->where))) {
       
   149 					if (isPrependingInputAttributes()) writeInputAttributes();
       
   150 					writeOutputAttributes();
       
   151 					if (isAppendingInputAttributes()) writeInputAttributes();
       
   152 				}
   109 
   153 
   110 				// TODO: evaluate XPath expression
   154 				resetRecordElement();
   111 				// TODO: write record to output, if the XPath condition was met
       
   112 				// TODO: clean record node in DOM
       
   113 				currentAttributeIndex = 0;
   155 				currentAttributeIndex = 0;
   114 			}
   156 			}
   115 		} else {
   157 		} else {
   116 			relationalWriter->writeAttribute(value);
   158 			relationalWriter->writeAttribute(value);
   117 		}
   159 		}