streamlet-examples/xpath.cpp
branchv_0
changeset 67 0766d298eb1c
parent 65 6944a03fb883
child 68 5d3d57d9c323
--- a/streamlet-examples/xpath.cpp	Mon Jan 27 00:43:39 2020 +0100
+++ b/streamlet-examples/xpath.cpp	Tue Jan 28 14:26:39 2020 +0100
@@ -17,13 +17,49 @@
 
 #include "streamlet-common.h"
 
+#include <unistd.h>
+#include <regex>
 #include <libxml++-2.6/libxml++/libxml++.h>
 
 class XPathStreamlet : public Streamlet {
+private:
+	xmlpp::Node::PrefixNsMap ns;
+
+	void findXmlnsInEnvironment() {
+		std::regex xmlnsEnvPattern("xmlns_(.*)=(.*)");
+		std::cmatch match;
+		for (char **env = environ; *env; env++) if (std::regex_match(*env, match, xmlnsEnvPattern)) ns[std::string(match[1])] = match[2];
+	}
+
+	void findXmlnsInOptions() {
+		for (Option o : getOptions(std::wregex(L"xmlns[:_](.*)"))) ns[convertor.to_bytes(o.nameMatch[1])] = convertor.to_bytes(o.value);
+		for (Option o : getOptions(std::wregex(L"xmlns"), std::wregex(L"([^:]+):(.*)"))) ns[convertor.to_bytes(o.valueMatch[1])] = convertor.to_bytes(o.valueMatch[2]);
+	}
+
+	class XPathAttribute {
+	public:
+
+		std::wstring name;
+		std::wstring xpath;
+	};
+
+	std::vector<XPathAttribute> xpathAttributes;
+
+protected:
 
 	std::vector<AttributeMetadata> getOutputAttributesMetadata() override {
+		findXmlnsInEnvironment();
+		findXmlnsInOptions();
+
 		std::vector<AttributeMetadata> oam;
-		oam.push_back({getAlias(0, L"xpath"), L"string"});
+
+		std::vector<Option> attributeOptions = getOptions(L"attribute");
+		for (int i = 0, limit = attributeOptions.size(); i < limit; i++) {
+			std::wstring alias = getAlias(i, attributeOptions[i].value);
+			xpathAttributes.push_back({alias, attributeOptions[i].value});
+			oam.push_back({alias, STRING});
+		}
+
 		return oam;
 	}
 
@@ -34,11 +70,19 @@
 			xmlpp::DomParser parser;
 			parser.parse_file(convertor.to_bytes(currentFile));
 			xmlpp::Element* root = parser.get_document()->get_root_node();
-			oa.push_back({L"XML OK", false});
-		} catch (...) {
-			oa.push_back({L"invalid XML", true});
+
+			for (XPathAttribute xpathAttribute : xpathAttributes) {
+				// TODO: support various modes like in XMLTableCommand
+				std::wstring result = convertor.from_bytes(root->eval_to_string(convertor.to_bytes(xpathAttribute.xpath), ns));
+				oa.push_back({result, false});
+			}
+		} catch (xmlpp::parse_error& e) {
+			for (XPathAttribute xpathAttribute : xpathAttributes) oa.push_back({L"", true});
+			// invalid XML → xmlpp::parse_error → just skip this file
+			// invalid XPath → xmlpp::exception → failure
 		}
 
+
 		return oa;
 	}
 };