src/XMLDocumentConstructor.h
branchv_0
changeset 29 9254988f9382
parent 26 84ff7c97bfdc
child 30 f5ac2d29eeb4
equal deleted inserted replaced
28:8f1da1ce3ca5 29:9254988f9382
    18 
    18 
    19 #include <codecvt>
    19 #include <codecvt>
    20 #include <vector>
    20 #include <vector>
    21 
    21 
    22 #include <libxml++-2.6/libxml++/libxml++.h>
    22 #include <libxml++-2.6/libxml++/libxml++.h>
    23 #include <yaml.h>
    23 #include <cbor.h>
    24 
    24 
    25 #include "XMLNameCodec.h"
    25 #include "XMLNameCodec.h"
    26 
    26 
    27 namespace relpipe {
    27 namespace relpipe {
    28 namespace in {
    28 namespace in {
    30 
    30 
    31 class XMLDocumentConstructor {
    31 class XMLDocumentConstructor {
    32 private:
    32 private:
    33 	std::istream* input = nullptr;
    33 	std::istream* input = nullptr;
    34 	xmlpp::DomParser* parser = nullptr;
    34 	xmlpp::DomParser* parser = nullptr;
    35 	yaml_parser_t yamlParser;
       
    36 	XMLNameCodec nameCodec;
    35 	XMLNameCodec nameCodec;
    37 
    36 
    38 	enum class Mode {
    37 	std::string rootName = "cbor";
    39 		ROOT,
       
    40 		SEQUENCE,
       
    41 		MAPPING,
       
    42 		MAP_KEY
       
    43 	};
       
    44 
       
    45 	std::string rootName = "yaml";
       
    46 	xmlpp::Element* current;
    38 	xmlpp::Element* current;
    47 	std::vector<Mode> mode;
       
    48 
       
    49 	static int readFromInput(void* instance, unsigned char* buffer, size_t size, size_t* length) {
       
    50 		std::istream* input = ((XMLDocumentConstructor*) instance)->input;
       
    51 		input->read((char*) buffer, size);
       
    52 		*length = input->gcount();
       
    53 		return (input->good() || input->eof()) ? 1 : 0;
       
    54 	}
       
    55 
    39 
    56 	/**
    40 	/**
    57 	 * Both YAML and XML strings are in UTF-8.
    41 	 * Both CBOR and XML strings are in UTF-8.
    58 	 */
    42 	 */
    59 	const char* y2x(yaml_char_t* value) {
    43 	const char* c2x(char* value) { // FIXME: cbor type
    60 		return value ? (const char*) value : "";
    44 		return value ? (const char*) value : "";
    61 	}
    45 	}
    62 
    46 
    63 	const Glib::ustring y2xname(yaml_char_t* value) {
    47 	const Glib::ustring c2xname(char* value) { // FIXME: cbor type
    64 		return nameCodec.encode(y2x(value));
    48 		return nameCodec.encode(c2x(value));
    65 	}
    49 	}
    66 
    50 
    67 	xmlpp::Element* parentOrSelf(xmlpp::Element* current) {
    51 	xmlpp::Element* parentOrSelf(xmlpp::Element* current) {
    68 		return current->get_parent() == nullptr ? current : current->get_parent();
    52 		return current->get_parent() == nullptr ? current : current->get_parent();
    69 	}
    53 	}
    70 
    54 
    71 public:
    55 public:
    72 
    56 
    73 	XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) {
    57 	XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) {
    74 		yaml_parser_initialize(&yamlParser);
    58 		// cbor_item_t * root = cbor_new_definite_map(2);
    75 		yaml_parser_set_input(&yamlParser, readFromInput, (void*) this);
    59 		// FIXME: initialize CBOR parser
    76 	}
    60 	}
    77 
    61 
    78 	virtual ~XMLDocumentConstructor() {
    62 	virtual ~XMLDocumentConstructor() {
    79 		yaml_parser_delete(&yamlParser);
    63 		// FIXME: destroy CBOR parser
    80 	}
    64 	}
    81 
    65 
    82 	void setOption(const std::string& uri, const std::string& value) {
    66 	void setOption(const std::string& uri, const std::string& value) {
    83 		if (uri == "root-name") rootName = value;
    67 		if (uri == "root-name") rootName = value;
    84 		else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“");
    68 		else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“");
    85 	}
    69 	}
    86 
    70 
    87 	void process() {
    71 	void process() {
    88 		current = parser->get_document()->create_root_node(rootName);
    72 		current = parser->get_document()->create_root_node(rootName);
    89 		mode.push_back(Mode::ROOT);
       
    90 		std::string itemName;
       
    91 
       
    92 		while (true) {
       
    93 			yaml_event_t event;
       
    94 
       
    95 			if (!yaml_parser_parse(&yamlParser, &event)) {
       
    96 				// FIXME: throw exception
       
    97 				return;
       
    98 			}
       
    99 
       
   100 
       
   101 			if (event.type == YAML_STREAM_END_EVENT) {
       
   102 				yaml_event_delete(&event);
       
   103 				break;
       
   104 			} else if (event.type == YAML_STREAM_START_EVENT) {
       
   105 			} else if (event.type == YAML_NO_EVENT) {
       
   106 				current->add_child("null"); // TODO: null?
       
   107 			} else if (event.type == YAML_DOCUMENT_START_EVENT) {
       
   108 			} else if (event.type == YAML_DOCUMENT_END_EVENT) {
       
   109 			} else if (event.type == YAML_ALIAS_EVENT) {
       
   110 				// TODO: alias?
       
   111 			} else if (event.type == YAML_SCALAR_EVENT) {
       
   112 				if (mode.back() == Mode::SEQUENCE) {
       
   113 					current->add_child(itemName)->add_child_text(y2x(event.data.scalar.value));
       
   114 				} else if (mode.back() == Mode::MAPPING) {
       
   115 					current = current->add_child(y2xname(event.data.scalar.value));
       
   116 					mode.push_back(Mode::MAP_KEY);
       
   117 				} else if (mode.back() == Mode::MAP_KEY) {
       
   118 					current->add_child_text(y2x(event.data.scalar.value));
       
   119 					current = parentOrSelf(current);
       
   120 					mode.pop_back();
       
   121 				} else if (mode.back() == Mode::ROOT) {
       
   122 					current->add_child_text(y2x(event.data.scalar.value));
       
   123 				} else {
       
   124 					// TODO: process YAML_SCALAR_EVENT
       
   125 				}
       
   126 
       
   127 			} else if (event.type == YAML_SEQUENCE_START_EVENT) {
       
   128 				xmlpp::Element* parent = current->get_parent();
       
   129 				if (parent) {
       
   130 					itemName = current->get_name();
       
   131 					parent->remove_child(current);
       
   132 					current = parent;
       
   133 				} else {
       
   134 					itemName = "item";
       
   135 				}
       
   136 				if (mode.back() == Mode::MAP_KEY) mode.pop_back();
       
   137 				mode.push_back(Mode::SEQUENCE);
       
   138 			} else if (event.type == YAML_SEQUENCE_END_EVENT) {
       
   139 				mode.pop_back(); // TODO: assert sequence?
       
   140 			} else if (event.type == YAML_MAPPING_START_EVENT) {
       
   141 
       
   142 				if (mode.back() == Mode::ROOT) {
       
   143 				} else if (mode.back() == Mode::SEQUENCE) {
       
   144 					current = current->add_child(itemName);
       
   145 				} else if (mode.back() == Mode::MAP_KEY) {
       
   146 					mode.pop_back();
       
   147 				} else {
       
   148 					// TODO: map might be a key of another map → wrap/nest
       
   149 				}
       
   150 
       
   151 				mode.push_back(Mode::MAPPING);
       
   152 			} else if (event.type == YAML_MAPPING_END_EVENT) {
       
   153 				current = parentOrSelf(current);
       
   154 				mode.pop_back(); // TODO: assert map?
       
   155 			} else {
       
   156 				// TODO: unsupported type?
       
   157 			}
       
   158 
       
   159 			yaml_event_delete(&event);
       
   160 		}
       
   161 
       
   162 
       
   163 	}
    73 	}
   164 };
    74 };
   165 
    75 
   166 }
    76 }
   167 }
    77 }