|
17 | 17 |
|
18 | 18 | #include "mtconnect/entity/xml_parser.hpp"
|
19 | 19 |
|
| 20 | +#include <boost/spirit/include/qi_numeric.hpp> |
| 21 | +#include <boost/spirit/include/qi_parse.hpp> |
| 22 | + |
20 | 23 | #include <libxml/parser.h>
|
21 | 24 | #include <libxml/xpath.h>
|
22 | 25 | #include <libxml/xpathInternals.h>
|
@@ -88,6 +91,81 @@ namespace mtconnect::entity {
|
88 | 91 | return content;
|
89 | 92 | }
|
90 | 93 |
|
| 94 | + template <typename P, typename A> |
| 95 | + static inline bool isType(const string &str, const P &parser, A &value) |
| 96 | + { |
| 97 | + std::string::const_iterator first(str.cbegin()), last(str.cend()); |
| 98 | + return boost::spirit::qi::parse(first, last, parser, value) && first == last; |
| 99 | + } |
| 100 | + |
| 101 | + static void parseDataSet(xmlNodePtr node, DataSet &dataSet, bool table, bool cell = false) |
| 102 | + { |
| 103 | + for (xmlNodePtr child = node->children; child; child = child->next) |
| 104 | + { |
| 105 | + if (child->type == XML_ELEMENT_NODE && |
| 106 | + ((!cell && xmlStrcmp(child->name, BAD_CAST "Entry") == 0) || |
| 107 | + (cell && xmlStrcmp(child->name, BAD_CAST "Cell") == 0))) |
| 108 | + { |
| 109 | + // Get the key for the entry |
| 110 | + string key; |
| 111 | + for (xmlAttrPtr attr = child->properties; attr; attr = attr->next) |
| 112 | + { |
| 113 | + if (attr->type == XML_ATTRIBUTE_NODE) |
| 114 | + { |
| 115 | + string name((const char *)attr->name); |
| 116 | + if (name != "key") |
| 117 | + { |
| 118 | + throw EntityError("parseDataSet: Expecting ksy for data set Entry: " + |
| 119 | + string((const char *)node->name)); |
| 120 | + } |
| 121 | + key = string((const char *)attr->children->content); |
| 122 | + break; |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + /// TODO: Add support for tables |
| 127 | + DataSetValue value; |
| 128 | + auto valueNode = child->children; |
| 129 | + if (valueNode) |
| 130 | + { |
| 131 | + if (table && !cell) |
| 132 | + { |
| 133 | + DataSet &ds = value.emplace<DataSet>(); |
| 134 | + parseDataSet(child, ds, true, true); |
| 135 | + } |
| 136 | + else if (valueNode->type == XML_TEXT_NODE) |
| 137 | + { |
| 138 | + string text = ((const char *)valueNode->content); |
| 139 | + trim(text); |
| 140 | + |
| 141 | + if (int64_t v; isType(text, boost::spirit::long_long, v)) |
| 142 | + { |
| 143 | + value = v; |
| 144 | + } |
| 145 | + else if (double v; isType(text, boost::spirit::double_, v)) |
| 146 | + { |
| 147 | + value = v; |
| 148 | + } |
| 149 | + else |
| 150 | + { |
| 151 | + value = text; |
| 152 | + } |
| 153 | + } |
| 154 | + else |
| 155 | + { |
| 156 | + LOG(warning) << "Invalid content for data set"; |
| 157 | + } |
| 158 | + } |
| 159 | + dataSet.emplace(key, value); |
| 160 | + } |
| 161 | + else |
| 162 | + { |
| 163 | + throw EntityError("parseDataSet: Expecting Entry for data set: " + |
| 164 | + string((const char *)node->name)); |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | + |
91 | 169 | EntityPtr XmlParser::parseXmlNode(FactoryPtr factory, xmlNodePtr node, ErrorList &errors,
|
92 | 170 | bool parseNamespaces)
|
93 | 171 | {
|
@@ -165,7 +243,12 @@ namespace mtconnect::entity {
|
165 | 243 | }
|
166 | 244 | }
|
167 | 245 |
|
168 |
| - if (simple) |
| 246 | + if (ef->isDataSet(name)) |
| 247 | + { |
| 248 | + auto ds = &properties[name].emplace<DataSet>(); |
| 249 | + parseDataSet(child, *ds, ef->isTable(name)); |
| 250 | + } |
| 251 | + else if (simple) |
169 | 252 | {
|
170 | 253 | if (child->children != nullptr && child->children->content != nullptr)
|
171 | 254 | {
|
|
0 commit comments