15 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 */ |
16 */ |
17 |
17 |
18 #include "streamlet-common.h" |
18 #include "streamlet-common.h" |
19 |
19 |
|
20 #include <unistd.h> |
|
21 #include <regex> |
20 #include <libxml++-2.6/libxml++/libxml++.h> |
22 #include <libxml++-2.6/libxml++/libxml++.h> |
21 |
23 |
22 class XPathStreamlet : public Streamlet { |
24 class XPathStreamlet : public Streamlet { |
|
25 private: |
|
26 xmlpp::Node::PrefixNsMap ns; |
|
27 |
|
28 void findXmlnsInEnvironment() { |
|
29 std::regex xmlnsEnvPattern("xmlns_(.*)=(.*)"); |
|
30 std::cmatch match; |
|
31 for (char **env = environ; *env; env++) if (std::regex_match(*env, match, xmlnsEnvPattern)) ns[std::string(match[1])] = match[2]; |
|
32 } |
|
33 |
|
34 void findXmlnsInOptions() { |
|
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]); |
|
37 } |
|
38 |
|
39 class XPathAttribute { |
|
40 public: |
|
41 |
|
42 std::wstring name; |
|
43 std::wstring xpath; |
|
44 }; |
|
45 |
|
46 std::vector<XPathAttribute> xpathAttributes; |
|
47 |
|
48 protected: |
23 |
49 |
24 std::vector<AttributeMetadata> getOutputAttributesMetadata() override { |
50 std::vector<AttributeMetadata> getOutputAttributesMetadata() override { |
|
51 findXmlnsInEnvironment(); |
|
52 findXmlnsInOptions(); |
|
53 |
25 std::vector<AttributeMetadata> oam; |
54 std::vector<AttributeMetadata> oam; |
26 oam.push_back({getAlias(0, L"xpath"), L"string"}); |
55 |
|
56 std::vector<Option> attributeOptions = getOptions(L"attribute"); |
|
57 for (int i = 0, limit = attributeOptions.size(); i < limit; i++) { |
|
58 std::wstring alias = getAlias(i, attributeOptions[i].value); |
|
59 xpathAttributes.push_back({alias, attributeOptions[i].value}); |
|
60 oam.push_back({alias, STRING}); |
|
61 } |
|
62 |
27 return oam; |
63 return oam; |
28 } |
64 } |
29 |
65 |
30 std::vector<OutputAttribute> getOutputAttributes() override { |
66 std::vector<OutputAttribute> getOutputAttributes() override { |
31 std::vector<OutputAttribute> oa; |
67 std::vector<OutputAttribute> oa; |
32 |
68 |
33 try { |
69 try { |
34 xmlpp::DomParser parser; |
70 xmlpp::DomParser parser; |
35 parser.parse_file(convertor.to_bytes(currentFile)); |
71 parser.parse_file(convertor.to_bytes(currentFile)); |
36 xmlpp::Element* root = parser.get_document()->get_root_node(); |
72 xmlpp::Element* root = parser.get_document()->get_root_node(); |
37 oa.push_back({L"XML OK", false}); |
73 |
38 } catch (...) { |
74 for (XPathAttribute xpathAttribute : xpathAttributes) { |
39 oa.push_back({L"invalid XML", true}); |
75 // TODO: support various modes like in XMLTableCommand |
|
76 std::wstring result = convertor.from_bytes(root->eval_to_string(convertor.to_bytes(xpathAttribute.xpath), ns)); |
|
77 oa.push_back({result, false}); |
|
78 } |
|
79 } catch (xmlpp::parse_error& e) { |
|
80 for (XPathAttribute xpathAttribute : xpathAttributes) oa.push_back({L"", true}); |
|
81 // invalid XML → xmlpp::parse_error → just skip this file |
|
82 // invalid XPath → xmlpp::exception → failure |
40 } |
83 } |
|
84 |
41 |
85 |
42 return oa; |
86 return oa; |
43 } |
87 } |
44 }; |
88 }; |
45 |
89 |