--- 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;
}
};