streamlet-examples/xpath.cpp
branchv_0
changeset 68 5d3d57d9c323
parent 67 0766d298eb1c
child 70 018e2609f5bb
equal deleted inserted replaced
67:0766d298eb1c 68:5d3d57d9c323
    34 	void findXmlnsInOptions() {
    34 	void findXmlnsInOptions() {
    35 		for (Option o : getOptions(std::wregex(L"xmlns[:_](.*)"))) ns[convertor.to_bytes(o.nameMatch[1])] = convertor.to_bytes(o.value);
    35 		for (Option o : getOptions(std::wregex(L"xmlns[:_](.*)"))) ns[convertor.to_bytes(o.nameMatch[1])] = convertor.to_bytes(o.value);
    36 		for (Option o : getOptions(std::wregex(L"xmlns"), std::wregex(L"([^:]+):(.*)"))) ns[convertor.to_bytes(o.valueMatch[1])] = convertor.to_bytes(o.valueMatch[2]);
    36 		for (Option o : getOptions(std::wregex(L"xmlns"), std::wregex(L"([^:]+):(.*)"))) ns[convertor.to_bytes(o.valueMatch[1])] = convertor.to_bytes(o.valueMatch[2]);
    37 	}
    37 	}
    38 
    38 
       
    39 	// Modes should share the logic of relpipe-in-xmltable
       
    40 
       
    41 	enum class Mode {
       
    42 		STRING,
       
    43 		BOOLEAN,
       
    44 		// TODO: support also XML number, when we have a rational or decimal numbers in Relational pipes
       
    45 		RAW_XML,
       
    46 		LINE_NUMBER,
       
    47 		XPATH
       
    48 	};
       
    49 
       
    50 	Mode toMode(std::wstring modeName) {
       
    51 		if (modeName == L"string") return Mode::STRING;
       
    52 		else if (modeName == L"boolean") return Mode::BOOLEAN;
       
    53 		else if (modeName == L"raw-xml") return Mode::RAW_XML;
       
    54 		else if (modeName == L"line-number") return Mode::LINE_NUMBER;
       
    55 		else if (modeName == L"xpath") return Mode::XPATH;
       
    56 		else throw std::invalid_argument("Unsupported mode: " + convertor.to_bytes(modeName));
       
    57 	}
       
    58 
       
    59 	std::wstring toType(Mode mode) {
       
    60 		if (mode == Mode::BOOLEAN) return BOOLEAN;
       
    61 		else if (mode == Mode::LINE_NUMBER) return INTEGER;
       
    62 		else return STRING;
       
    63 	}
       
    64 
       
    65 	// TODO: should not be done in particular streamlets but in the worker
       
    66 	std::wstring toNullValue(std::wstring type) {
       
    67 		if (type == BOOLEAN) return L"false";
       
    68 		else if (type == INTEGER) return L"0";
       
    69 		else return L"";
       
    70 	}
       
    71 
    39 	class XPathAttribute {
    72 	class XPathAttribute {
    40 	public:
    73 	public:
    41 
    74 
    42 		std::wstring name;
    75 		std::wstring name;
    43 		std::wstring xpath;
    76 		std::wstring xpath;
       
    77 		Mode mode = Mode::STRING;
    44 	};
    78 	};
    45 
    79 
    46 	std::vector<XPathAttribute> xpathAttributes;
    80 	std::vector<XPathAttribute> xpathAttributes;
    47 
    81 
    48 protected:
    82 protected:
    51 		findXmlnsInEnvironment();
    85 		findXmlnsInEnvironment();
    52 		findXmlnsInOptions();
    86 		findXmlnsInOptions();
    53 
    87 
    54 		std::vector<AttributeMetadata> oam;
    88 		std::vector<AttributeMetadata> oam;
    55 
    89 
       
    90 		std::vector<Option> modeOptions = getOptions(L"mode");
    56 		std::vector<Option> attributeOptions = getOptions(L"attribute");
    91 		std::vector<Option> attributeOptions = getOptions(L"attribute");
    57 		for (int i = 0, limit = attributeOptions.size(); i < limit; i++) {
    92 		for (int i = 0, limit = attributeOptions.size(); i < limit; i++) {
       
    93 			Mode mode = i < modeOptions.size() ? toMode(modeOptions[i].value) : Mode::STRING;
    58 			std::wstring alias = getAlias(i, attributeOptions[i].value);
    94 			std::wstring alias = getAlias(i, attributeOptions[i].value);
    59 			xpathAttributes.push_back({alias, attributeOptions[i].value});
    95 			xpathAttributes.push_back({alias, attributeOptions[i].value, mode});
    60 			oam.push_back({alias, STRING});
    96 			oam.push_back({alias, toType(mode)});
    61 		}
    97 		}
    62 
    98 
    63 		return oam;
    99 		return oam;
    64 	}
   100 	}
    65 
   101 
    70 			xmlpp::DomParser parser;
   106 			xmlpp::DomParser parser;
    71 			parser.parse_file(convertor.to_bytes(currentFile));
   107 			parser.parse_file(convertor.to_bytes(currentFile));
    72 			xmlpp::Element* root = parser.get_document()->get_root_node();
   108 			xmlpp::Element* root = parser.get_document()->get_root_node();
    73 
   109 
    74 			for (XPathAttribute xpathAttribute : xpathAttributes) {
   110 			for (XPathAttribute xpathAttribute : xpathAttributes) {
    75 				// TODO: support various modes like in XMLTableCommand
   111 				std::string xpath = convertor.to_bytes(xpathAttribute.xpath);
    76 				std::wstring result = convertor.from_bytes(root->eval_to_string(convertor.to_bytes(xpathAttribute.xpath), ns));
   112 				std::wstring result;
       
   113 				bool isNull = false;
       
   114 
       
   115 				if (xpathAttribute.mode == Mode::STRING) {
       
   116 					result = convertor.from_bytes(root->eval_to_string(xpath, ns));
       
   117 				} else if (xpathAttribute.mode == Mode::BOOLEAN) {
       
   118 					result = root->eval_to_boolean(xpath, ns) ? L"true" : L"false";
       
   119 				} else if (xpathAttribute.mode == Mode::LINE_NUMBER) {
       
   120 					xmlpp::NodeSet attributeNodes = root->find(xpath, ns);
       
   121 					if (attributeNodes.size()) {
       
   122 						result = std::to_wstring(attributeNodes[0]->get_line());
       
   123 					} else {
       
   124 						result = L"0";
       
   125 						isNull = true;
       
   126 					}
       
   127 				} else if (xpathAttribute.mode == Mode::XPATH) {
       
   128 					xmlpp::NodeSet attributeNodes = root->find(xpath, ns);
       
   129 					if (attributeNodes.size()) {
       
   130 						result = convertor.from_bytes(attributeNodes[0]->get_path());
       
   131 					} else {
       
   132 						result = L"";
       
   133 						isNull = true;
       
   134 					}
       
   135 				} else if (xpathAttribute.mode == Mode::RAW_XML) {
       
   136 					throw std::logic_error("Raw XML mode is not yet implemented."); // TODO: implement also RAW_XML
       
   137 				} else {
       
   138 					throw std::logic_error("Unsupported mode."); // should never happer
       
   139 				}
       
   140 
    77 				oa.push_back({result, false});
   141 				oa.push_back({result, false});
    78 			}
   142 			}
    79 		} catch (xmlpp::parse_error& e) {
   143 		} catch (xmlpp::parse_error& e) {
    80 			for (XPathAttribute xpathAttribute : xpathAttributes) oa.push_back({L"", true});
   144 			for (XPathAttribute xpathAttribute : xpathAttributes) oa.push_back({toNullValue(toType(xpathAttribute.mode)), true});
    81 			// invalid XML → xmlpp::parse_error → just skip this file
   145 			// invalid XML → xmlpp::parse_error → just skip this file
    82 			// invalid XPath → xmlpp::exception → failure
   146 			// invalid XPath → xmlpp::exception → failure
    83 		}
   147 		}
    84 
   148 
    85 
   149