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 |