Subsonic API: switch from property_tree to Wt::Json to properly report empty arrays/nodes
This commit is contained in:
@@ -19,7 +19,10 @@
|
|||||||
|
|
||||||
#include "SubsonicResponse.hpp"
|
#include "SubsonicResponse.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <Wt/Json/Array.h>
|
||||||
|
#include <Wt/Json/Object.h>
|
||||||
|
#include <Wt/Json/Value.h>
|
||||||
|
#include <Wt/Json/Serializer.h>
|
||||||
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/xml_parser.hpp>
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
@@ -192,74 +195,96 @@ Response::createArrayNode(const std::string& key)
|
|||||||
void
|
void
|
||||||
Response::write(std::ostream& os, ResponseFormat format)
|
Response::write(std::ostream& os, ResponseFormat format)
|
||||||
{
|
{
|
||||||
std::function<boost::property_tree::ptree(const Response::Node&, ResponseFormat)> nodeToPropertyTree = [&] (const Response::Node& node, ResponseFormat format)
|
switch (format)
|
||||||
|
{
|
||||||
|
case ResponseFormat::xml:
|
||||||
|
writeXML(os);
|
||||||
|
break;
|
||||||
|
case ResponseFormat::json:
|
||||||
|
writeJSON(os);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Response::writeXML(std::ostream& os)
|
||||||
|
{
|
||||||
|
std::function<boost::property_tree::ptree(const Response::Node&)> nodeToPropertyTree = [&] (const Response::Node& node)
|
||||||
{
|
{
|
||||||
boost::property_tree::ptree res;
|
boost::property_tree::ptree res;
|
||||||
|
|
||||||
for (auto itAttribute : node._attributes)
|
for (auto itAttribute : node._attributes)
|
||||||
{
|
res.put("<xmlattr>." + itAttribute.first, itAttribute.second);
|
||||||
std::string key {format == ResponseFormat::xml ? "<xmlattr>." : ""};
|
|
||||||
|
|
||||||
key += itAttribute.first;
|
|
||||||
|
|
||||||
res.put(key, itAttribute.second);
|
|
||||||
}
|
|
||||||
if (!node._value.empty())
|
if (!node._value.empty())
|
||||||
{
|
{
|
||||||
if (format == ResponseFormat::json)
|
res.put_value(node._value);
|
||||||
res.put("value", node._value);
|
|
||||||
else
|
|
||||||
res.put_value(node._value);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto itChildNode : node._children)
|
for (auto itChildNode : node._children)
|
||||||
{
|
{
|
||||||
for (const Response::Node& childNode : itChildNode.second)
|
for (const Response::Node& childNode : itChildNode.second)
|
||||||
res.add_child(itChildNode.first, nodeToPropertyTree(childNode, format));
|
res.add_child(itChildNode.first, nodeToPropertyTree(childNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto itChildArrayNode : node._childrenArrays)
|
for (auto itChildArrayNode : node._childrenArrays)
|
||||||
{
|
{
|
||||||
const std::vector<Response::Node>& childArrayNodes {itChildArrayNode .second};
|
const std::vector<Response::Node>& childArrayNodes {itChildArrayNode .second};
|
||||||
|
|
||||||
if (format == ResponseFormat::json)
|
for (const Response::Node& childNode : childArrayNodes )
|
||||||
{
|
res.add_child(itChildArrayNode.first, nodeToPropertyTree(childNode));
|
||||||
boost::property_tree::ptree array;
|
|
||||||
|
|
||||||
for (const Response::Node& childNode : childArrayNodes )
|
|
||||||
array.push_back(std::make_pair("", nodeToPropertyTree(childNode, format)));
|
|
||||||
|
|
||||||
res.add_child(itChildArrayNode.first, array);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const Response::Node& childNode : childArrayNodes )
|
|
||||||
res.add_child(itChildArrayNode.first, nodeToPropertyTree(childNode, format));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boost::property_tree::ptree root {nodeToPropertyTree(_root)};
|
||||||
|
boost::property_tree::write_xml(os, root);
|
||||||
|
}
|
||||||
|
|
||||||
boost::property_tree::ptree root {nodeToPropertyTree(_root, format)};
|
void
|
||||||
|
Response::writeJSON(std::ostream& os)
|
||||||
|
{
|
||||||
|
namespace Json = Wt::Json;
|
||||||
|
|
||||||
switch (format)
|
std::function<Json::Object(const Response::Node&)> nodeToJsonObject = [&] (const Response::Node& node)
|
||||||
{
|
{
|
||||||
case ResponseFormat::xml:
|
Json::Object res;
|
||||||
boost::property_tree::write_xml(os, root);
|
|
||||||
break;
|
for (auto itAttribute : node._attributes)
|
||||||
case ResponseFormat::json:
|
res[itAttribute.first] = Json::Value {itAttribute.second};
|
||||||
|
|
||||||
|
if (!node._value.empty())
|
||||||
{
|
{
|
||||||
// property_tree does not support empty json array
|
res["value"] = Json::Value {node._value};
|
||||||
std::ostringstream oss;
|
|
||||||
boost::property_tree::write_json(oss, root);
|
|
||||||
os << std::regex_replace(oss.str(), std::regex {R"(\[[\r\n]*\s*\"\"[\r\n]*\s*\])"}, R"({})");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
for (auto itChildNode : node._children)
|
||||||
|
{
|
||||||
|
for (const Response::Node& childNode : itChildNode.second)
|
||||||
|
res[itChildNode.first] = nodeToJsonObject(childNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto itChildArrayNode : node._childrenArrays)
|
||||||
|
{
|
||||||
|
const std::vector<Response::Node>& childArrayNodes {itChildArrayNode .second};
|
||||||
|
|
||||||
|
Json::Array array;
|
||||||
|
for (const Response::Node& childNode : childArrayNodes )
|
||||||
|
array.emplace_back(nodeToJsonObject(childNode));
|
||||||
|
|
||||||
|
res[itChildArrayNode.first] = std::move(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
Json::Object root {nodeToJsonObject(_root)};
|
||||||
|
os << Json::serialize(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -101,10 +101,12 @@ class Response
|
|||||||
Node& createNode(const std::string& key);
|
Node& createNode(const std::string& key);
|
||||||
Node& createArrayNode(const std::string& key);
|
Node& createArrayNode(const std::string& key);
|
||||||
|
|
||||||
void writeJson(std::ostream& os);
|
|
||||||
void write(std::ostream& os, ResponseFormat format);
|
void write(std::ostream& os, ResponseFormat format);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void writeJSON(std::ostream& os);
|
||||||
|
void writeXML(std::ostream& os);
|
||||||
|
|
||||||
Response() = default;
|
Response() = default;
|
||||||
Node _root;
|
Node _root;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user