diff -r d6dbd5d50d43 -r 426054465916 src/XPathHandler.h --- a/src/XPathHandler.h Wed Dec 30 00:39:03 2020 +0100 +++ b/src/XPathHandler.h Wed Dec 30 01:28:45 2020 +0100 @@ -34,6 +34,7 @@ #include #include "Configuration.h" +#include "XMLNameCodec.h" namespace relpipe { namespace tr { @@ -41,14 +42,18 @@ class XPathHandler : public relpipe::reader::handlers::RelationalReaderStringHandler { private: + std::wstring_convert> convertor; // XML is in UTF-8 shared_ptr relationalWriter; Configuration configuration; - RelationConfiguration* currentRelationConfiguration; + RelationConfiguration* currentRelationConfiguration = nullptr; std::vector currentReaderMetadata; std::vector currentWriterMetadata; size_t currentAttributeIndex = 0; - + + xmlpp::DomParser dom; + xmlpp::Element* recordElement = nullptr; + relpipe::in::xmltable::XMLNameCodec xmlNameCodec; // TODO: move to a common library void copyInputAttributesToOutput() { for (auto rm : currentReaderMetadata) currentWriterMetadata.push_back({rm.getAttributeName(), relationalWriter->toTypeId(rm.getTypeName())}); @@ -63,6 +68,35 @@ return currentRelationConfiguration->inputAttributePolicy == InputAttributePolicy::Append; } + void resetRecordElement() { + if (recordElement) dom.get_document()->get_root_node()->remove_child(recordElement); + recordElement = dom.get_document()->get_root_node()->add_child("record"); + } + + const Glib::ustring s2x(relpipe::common::type::StringX value) { + return Glib::ustring(convertor.to_bytes(value)); + } + + const relpipe::common::type::StringX x2s(const Glib::ustring& value) { + return convertor.from_bytes(value); + } + + void writeInputAttributes() { + for (xmlpp::Node* attributeNode : recordElement->get_children()) { + if (xmlpp::Element * attributeElement = dynamic_cast (attributeNode)) { + auto value = attributeElement->get_child_text()->get_content(); + relationalWriter->writeAttribute(x2s(value)); + } + } + } + + void writeOutputAttributes() { + for (auto oa : currentRelationConfiguration->outputAttributes) { + auto value = recordElement->eval_to_string(s2x(oa.xpath)); + relationalWriter->writeAttribute(x2s(value)); + } + } + public: XPathHandler(shared_ptr relationalWriter, Configuration configuration) : relationalWriter(relationalWriter), configuration(configuration) { @@ -92,6 +126,8 @@ if (isAppendingInputAttributes()) copyInputAttributesToOutput(); // TODO: prepare DOM + dom.get_document()->create_root_node("relpipe-tr-xpath"); + resetRecordElement(); } relationalWriter->startRelation(name, currentWriterMetadata, true); @@ -101,15 +137,21 @@ if (currentRelationConfiguration) { relpipe::reader::handlers::AttributeMetadata attributeMetadata = currentReaderMetadata[currentAttributeIndex]; - // TODO: add attribute to DOM + xmlpp::Element* attributeElement = recordElement->add_child(xmlNameCodec.encode(s2x(attributeMetadata.getAttributeName()))); + attributeElement->set_attribute("name", s2x(attributeMetadata.getAttributeName())); + attributeElement->set_attribute("type", s2x(attributeMetadata.getTypeName())); + attributeElement->add_child_text(s2x(value)); currentAttributeIndex++; if (currentAttributeIndex == currentReaderMetadata.size()) { + if (currentRelationConfiguration->where.empty() || recordElement->eval_to_boolean(s2x(currentRelationConfiguration->where))) { + if (isPrependingInputAttributes()) writeInputAttributes(); + writeOutputAttributes(); + if (isAppendingInputAttributes()) writeInputAttributes(); + } - // TODO: evaluate XPath expression - // TODO: write record to output, if the XPath condition was met - // TODO: clean record node in DOM + resetRecordElement(); currentAttributeIndex = 0; } } else {