libcruft-util/json/pointer.cpp

60 lines
1.7 KiB
C++

#include "pointer.hpp"
#include "tree.hpp"
#include "../parse.hpp"
#include <algorithm>
#include <stdexcept>
///////////////////////////////////////////////////////////////////////////////
::json::tree::node&
util::json::pointer::resolve (std::string const &path,
::json::tree::node &root)
{
// we only handle fragment represenations currently, which start with a '#'
auto cursor = path.begin ();
if (cursor == path.end () || *cursor != '#')
throw std::invalid_argument ("must be fragment representation");
++cursor;
auto obj = &root;
// * step over each path segment
// * index into the current node
// * advance the node
// * repeat until we reach the end of the query string
for ( ; cursor != path.end (); ) {
// step over the delimiting '/'
if (*cursor != '/')
break;
++cursor;
// find the start of the next segment (or the end of the string)
// and extract the key.
auto next = std::find (cursor, path.end (), '/');
std::string const key { cursor, next };
// try to index into the node and advance the node we're operating on
switch (obj->type ()) {
case ::json::tree::OBJECT:
obj = &(*obj)[key];
break;
case ::json::tree::ARRAY:
obj = &(*obj)[util::parse<size_t> (key)];
break;
case ::json::tree::STRING:
case ::json::tree::NUMBER:
case ::json::tree::BOOLEAN:
case ::json::tree::NONE:
throw std::invalid_argument ("indexing into wrong type");
}
// step to the beginning of the next component
cursor = next;
}
return *obj;
}