gpxpath.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include <cstring>
  2. #include <fstream>
  3. #include <iostream>
  4. #include "Arguments.h"
  5. #include "XMLRawParser.h"
  6. // ----------------------------------------------------------------------------
  7. namespace gpxtools
  8. {
  9. class GPXPath : public XMLParserHandler
  10. {
  11. public:
  12. // -- Constructor -----------------------------------------------------------
  13. GPXPath() :
  14. _arguments("gpxrm [OPTION].. PATH [FILE]\nRead or set a path from a GPX-file.\n", "gpxpath v0.1", "Read or set a path from a GPX-file and display the result on standard output."),
  15. _value(_arguments, true, 'v', "value", "VALUE", "set path to a value", ""),
  16. _xmlParser(this),
  17. _update(false),
  18. _updating(false),
  19. _found(false),
  20. _updated(false)
  21. {
  22. }
  23. // -- Deconstructor ---------------------------------------------------------
  24. virtual ~GPXPath()
  25. {
  26. }
  27. // -- Properties ------------------------------------------------------------
  28. // -- Parse arguments -------------------------------------------------------
  29. bool processArguments(int argc, char *argv[])
  30. {
  31. std::vector<std::string> filenames;
  32. if (!_arguments.parse(argc,argv, filenames)) return false;
  33. _updating = !_value.value().empty();
  34. if (!checkArguments(filenames)) return false;
  35. if (filenames.empty())
  36. {
  37. if (!_xmlParser.parse(std::cin)) return false;
  38. }
  39. else
  40. {
  41. if (!parseFile(filenames.front())) return false;
  42. }
  43. return _found || _updated;
  44. }
  45. // -- Check arguments ---------------------------------------------------------
  46. bool checkArguments(std::vector<std::string> &filenames)
  47. {
  48. if (filenames.empty())
  49. {
  50. std::cerr << "Missing path to look for." << std::endl;
  51. return false;
  52. }
  53. _path = filenames.front();
  54. if (_updating)
  55. {
  56. _parent = getParent(_path);
  57. }
  58. filenames.erase(filenames.begin());
  59. if (filenames.size() > 1)
  60. {
  61. std::cerr << "Too many input files." << std::endl;
  62. return false;
  63. }
  64. return true;
  65. }
  66. // -- Parse a file ----------------------------------------------------------
  67. bool parseFile(const std::string &filename)
  68. {
  69. bool ok =false;
  70. std::ifstream file(filename);
  71. if (file.is_open())
  72. {
  73. ok = _xmlParser.parse(file);
  74. file.close();
  75. }
  76. else
  77. {
  78. std::cerr << "Unable to open: " << filename << std::endl;
  79. }
  80. return ok;
  81. }
  82. private:
  83. void store(const std::string &text)
  84. {
  85. std::cout << text;
  86. }
  87. public:
  88. // -- Callbacks -------------------------------------------------------------
  89. virtual void unhandled(const std::string &, const std::string &text)
  90. {
  91. if (_updating)
  92. {
  93. std::cout << text;
  94. }
  95. }
  96. virtual void startElement(const std::string &path, const std::string &text, const std::string &, const Attributes &)
  97. {
  98. if (_updating)
  99. {
  100. updateStartElement(path, text);
  101. }
  102. else
  103. {
  104. if (_path == path)
  105. {
  106. _text.clear();
  107. _found = true;
  108. }
  109. }
  110. }
  111. virtual void text(const std::string &path, const std::string &text)
  112. {
  113. if (_updating)
  114. {
  115. updateText(path, text);
  116. }
  117. else
  118. {
  119. if (_path == path) _text += text;
  120. }
  121. }
  122. virtual void endElement(const std::string &path, const std::string &text, const std::string &)
  123. {
  124. if (_updating)
  125. {
  126. updateEndElement(path, text);
  127. }
  128. else
  129. {
  130. if (_path == path)
  131. {
  132. XMLRawParser::trim(_text);
  133. std::cout << _text << std::endl;
  134. }
  135. }
  136. }
  137. private:
  138. std::string getParent(const std::string &path)
  139. {
  140. if (startsWith(path, "/gpx/metadata")) return "/gpx";
  141. if (startsWith(path, "/gpx/wpt")) return "/gpx/wpt";
  142. if (startsWith(path, "/gpx/rte/rtept")) return "/gpx/rte/rtept";
  143. if (startsWith(path, "/gpx/rte")) return "/gpx/rte";
  144. if (startsWith(path, "/gpx/trk/trkseg/trkpt")) return "/gpx/trk/trkseg/trkpt";
  145. if (startsWith(path, "/gpx/trk")) return "/gpx/trk";
  146. return std::string();
  147. }
  148. void updateStartElement(const std::string &path, const std::string &text)
  149. {
  150. if (path == _parent)
  151. {
  152. _update = true;
  153. }
  154. if (path == _path)
  155. {
  156. // Full match, reset the sub match
  157. _matched.clear();
  158. }
  159. else if (matchSubPath(path))
  160. {
  161. // Look for the largest sub match
  162. if (path.length() > _matched.length()) _matched = path;
  163. }
  164. else if (nextParent(path))
  165. {
  166. insertValue(_parent);
  167. _update = false;
  168. }
  169. std::cout << text;
  170. }
  171. void updateText(const std::string &path, const std::string &text)
  172. {
  173. // Skip text for matched path, it will be changed by the new value
  174. if (path != _path)
  175. {
  176. std::cout << text;
  177. }
  178. }
  179. void updateEndElement(const std::string &path, const std::string &text)
  180. {
  181. if (path == _path)
  182. {
  183. // Write new value for matched path
  184. std::cout << _value.value();
  185. _updated = true;
  186. _update = false;
  187. }
  188. else if (path == _matched)
  189. {
  190. // Close tag for the sub matched -> insert the tags and new value
  191. insertValue(path);
  192. _matched.clear();
  193. _updated = true;
  194. _update = false;
  195. }
  196. std::cout << text;
  197. }
  198. bool matchSubPath(const std::string &path)
  199. {
  200. if (!_update) return false;
  201. if (path.size() >= _path.size()) return false;
  202. return startsWith(_path, path);
  203. }
  204. bool nextParent(const std::string &path)
  205. {
  206. if (!_update) return false;
  207. if (startsWith(_path, "/gpx/metadata") &&
  208. ((startsWith(path, "/gpx/trk")) ||
  209. (startsWith(path, "/gpx/rte")) ||
  210. (startsWith(path, "/gpx/wpt")))) return true;
  211. if (!startsWith(_path, "/gpx/trk/trkseg") &&
  212. startsWith(path, "/gpx/trk/trkseg")) return true;
  213. if (!startsWith(_path, "/gpx/rte/rtept") &&
  214. startsWith(path, "/gpx/rte/rtept")) return true;
  215. return false;
  216. }
  217. bool startsWith(const std::string &str, const std::string &start)
  218. {
  219. return (str.compare(0, start.size(), start) == 0);
  220. }
  221. void insertValue(const std::string &path)
  222. {
  223. if (!matchSubPath(path)) return;
  224. buildTags(_path.substr(path.size() + 1)); // also remove first /
  225. }
  226. void buildTags(const std::string &tags)
  227. {
  228. std::size_t size = tags.find_first_of('/');
  229. if (size != std::string::npos)
  230. {
  231. const std::string name = tags.substr(0, size);
  232. std::cout << '<' << name << '>';
  233. buildTags(tags.substr(size + 1)); // also remove next /
  234. std::cout << "</" << name << '>';
  235. }
  236. else
  237. {
  238. std::cout << '<' << tags << '>' << _value.value() << "</" << tags << '>';
  239. }
  240. }
  241. // Members
  242. arg::Arguments _arguments;
  243. arg::Argument _value; // the new value
  244. XMLRawParser _xmlParser;
  245. std::string _path; // the search path
  246. std::string _parent; // the parent path of _path
  247. std::string _matched; // the matched sub path
  248. std::string _text; // the text of the path during querying
  249. bool _found;
  250. bool _updating; // the mode of the tool
  251. bool _update; // should the path be updated in the parent
  252. bool _updated; // is the path updated
  253. };
  254. }
  255. // -- Main program ------------------------------------------------------------
  256. int main(int argc, char *argv[])
  257. {
  258. gpxtools::GPXPath gpxPath;
  259. return gpxPath.processArguments(argc, argv) ? 0 : 1;
  260. }