use JSON container to hold all intermediate results:

- no hand-rolled GPX generation anymore
- render gpx thru a JSONContainer visitor pattern
- precursor to expose JSON containter as result from OSRM lib interface, cf. #1261
This commit is contained in:
Dennis Luxen 2014-11-24 15:15:57 +01:00
parent c581563230
commit 6859b53155
2 changed files with 162 additions and 31 deletions

View File

@ -29,31 +29,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define GPX_DESCRIPTOR_H
#include "BaseDescriptor.h"
#include "../DataStructures/JSONContainer.h"
#include "../Util/xml_renderer.hpp"
#include <iostream>
template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
{
private:
DescriptorConfig config;
FixedPointCoordinate current;
DataFacadeT *facade;
void AddRoutePoint(const FixedPointCoordinate &coordinate, std::vector<char> &output)
void AddRoutePoint(const FixedPointCoordinate &coordinate, JSON::Array &json_result)
{
const std::string route_point_head = "<rtept lat=\"";
const std::string route_point_middle = " lon=\"";
const std::string route_point_tail = "\"></rtept>";
JSON::Object json_lat;
JSON::Object json_lon;
JSON::Array json_row;
std::string tmp;
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
output.insert(output.end(), route_point_head.begin(), route_point_head.end());
output.insert(output.end(), tmp.begin(), tmp.end());
output.push_back('\"');
json_lat.values["_lat"] = tmp;
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
output.insert(output.end(), tmp.begin(), tmp.end());
output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
json_lon.values["_lon"] = tmp;
json_row.values.push_back(json_lat);
json_row.values.push_back(json_lon);
JSON::Object entry;
entry.values["rtept"] = json_row;
json_result.values.push_back(entry);
}
public:
@ -61,26 +66,13 @@ template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<D
void SetConfig(const DescriptorConfig &c) final { config = c; }
// TODO: reorder parameters
void Run(const RawRouteData &raw_route, http::Reply &reply) final
{
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
"\">"
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
" OpenStreetMap contributors (ODbL)</license></copyright>"
"</metadata>"
"<rte>");
reply.content.insert(reply.content.end(), header.begin(), header.end());
const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
(!raw_route.unpacked_path_segments.front().empty());
if (found_route)
JSON::Array json_result;
if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
{
AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
reply.content);
json_result);
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
{
@ -88,14 +80,13 @@ template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<D
{
const FixedPointCoordinate current_coordinate =
facade->GetCoordinateOfNode(path_data.node);
AddRoutePoint(current_coordinate, reply.content);
AddRoutePoint(current_coordinate, json_result);
}
}
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
reply.content);
json_result);
}
std::string footer("</rte></gpx>");
reply.content.insert(reply.content.end(), footer.begin(), footer.end());
JSON::gpx_render(reply.content, json_result);
}
};
#endif // GPX_DESCRIPTOR_H

140
Util/xml_renderer.hpp Normal file
View File

@ -0,0 +1,140 @@
/*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef XML_RENDERER_HPP
#define XML_RENDERER_HPP
#include "../DataStructures/JSONContainer.h"
#include "cast.hpp"
namespace JSON {
struct XMLToArrayRenderer : mapbox::util::static_visitor<>
{
explicit XMLToArrayRenderer(std::vector<char> &_out) : out(_out) {}
void operator()(const String &string) const
{
out.push_back('\"');
out.insert(out.end(), string.value.begin(), string.value.end());
out.push_back('\"');
}
void operator()(const Number &number) const
{
const std::string number_string = cast::double_fixed_to_string(number.value);
out.insert(out.end(), number_string.begin(), number_string.end());
}
void operator()(const Object &object) const
{
auto iterator = object.values.begin();
while (iterator != object.values.end())
{
if (iterator->first.at(0) != '_')
{
out.push_back('<');
out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
}
else
{
out.push_back(' ');
out.insert(out.end(), ++(*iterator).first.begin(), (*iterator).first.end());
out.push_back('=');
}
mapbox::util::apply_visitor(XMLToArrayRenderer(out), (*iterator).second);
if (iterator->first.at(0) != '_')
{
out.push_back('/');
out.push_back('>');
}
++iterator;
}
}
void operator()(const Array &array) const
{
std::vector<Value>::const_iterator iterator;
iterator = array.values.begin();
while (iterator != array.values.end())
{
mapbox::util::apply_visitor(XMLToArrayRenderer(out), *iterator);
++iterator;
}
}
void operator()(const True &) const
{
const std::string temp("true");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const False &) const
{
const std::string temp("false");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const Null &) const
{
const std::string temp("null");
out.insert(out.end(), temp.begin(), temp.end());
}
private:
std::vector<char> &out;
};
template<class JSONObject>
inline void xml_render(std::vector<char> &out, const JSONObject &object)
{
Value value = object;
mapbox::util::apply_visitor(XMLToArrayRenderer(out), value);
}
template<class JSONObject>
inline void gpx_render(std::vector<char> &out, const JSONObject &object)
{
// add header
const std::string header {"<?xml version=\"1.0\" encoding=\"UTF-8\"?><gpx creator=\"OSRM Routing Engine\""
" version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http:"
"//www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topogr"
"afix.com/GPX/1/1 gpx.xsd\"><metadata><copyright author=\"Project OSRM\"><lice"
"nse>Data (c) OpenStreetMap contributors (ODbL)</license></copyright></metadat"
"a><rte>"};
out.insert(out.end(), header.begin(), header.end());
xml_render(out, object);
const std::string footer {"</rte></gpx>"};
out.insert(out.end(), footer.begin(), footer.end());
}
} // namespace JSON
#endif // XML_RENDERER_HPP