Skip to content

Commit 6b57738

Browse files
author
Steve Hanson
committed
handle internal refs properly
1 parent fe1a29c commit 6b57738

File tree

8 files changed

+873
-528
lines changed

8 files changed

+873
-528
lines changed

bin/unittestschema/idandref.json

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"id": "http://example.com/root.json",
3+
"definitions": {
4+
"A": {
5+
"id": "#foo",
6+
"type": "integer"
7+
},
8+
"B": {
9+
"id": "other.json",
10+
"definitions": {
11+
"X": {
12+
"id": "#bar",
13+
"type": "boolean"
14+
},
15+
"Y": {
16+
"$ref": "#/definitions/X"
17+
},
18+
"W": {
19+
"$ref": "#/definitions/Y"
20+
},
21+
"Z": {
22+
"$ref": "#bar"
23+
},
24+
"N": {
25+
"properties": {
26+
"NX": {
27+
"$ref": "#/definitions/X"
28+
}
29+
}
30+
}
31+
}
32+
}
33+
},
34+
"properties": {
35+
"PA1": {
36+
"$ref": "http://example.com/root.json#/definitions/A"
37+
},
38+
"PA2": {
39+
"$ref": "#/definitions/A"
40+
},
41+
"PA3": {
42+
"$ref": "#foo"
43+
},
44+
"PX1": {
45+
"$ref": "#/definitions/B/definitions/X"
46+
},
47+
"PX2Y": {
48+
"$ref": "#/definitions/B/definitions/Y"
49+
},
50+
"PX3Z": {
51+
"$ref": "#/definitions/B/definitions/Z"
52+
},
53+
"PX4": {
54+
"$ref": "http://example.com/other.json#/definitions/X"
55+
},
56+
"PX5": {
57+
"$ref": "other.json#/definitions/X"
58+
},
59+
"PX6": {
60+
"$ref": "other.json#bar"
61+
},
62+
"PX7W": {
63+
"$ref": "#/definitions/B/definitions/W"
64+
},
65+
"PX8N": {
66+
"$ref": "#/definitions/B/definitions/N"
67+
}
68+
}
69+
}

include/rapidjson/pointer.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define RAPIDJSON_POINTER_H_
1717

1818
#include "document.h"
19+
#include "uri.h"
1920
#include "internal/itoa.h"
2021

2122
#ifdef __clang__
@@ -80,6 +81,8 @@ class GenericPointer {
8081
public:
8182
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
8283
typedef typename ValueType::Ch Ch; //!< Character type from Value
84+
typedef GenericUri<ValueType, Allocator> UriType;
85+
8386

8487
//! A token is the basic units of internal representation.
8588
/*!
@@ -520,6 +523,69 @@ class GenericPointer {
520523

521524
//@}
522525

526+
//!@name Compute URI
527+
//@{
528+
529+
//! Compute the in-scope URI for a subtree.
530+
// For use with JSON pointers into JSON schema documents.
531+
/*!
532+
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
533+
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
534+
\return Uri if it can be resolved. Otherwise null.
535+
536+
\note
537+
There are only 3 situations when a URI cannot be resolved:
538+
1. A value in the path is not an array nor object.
539+
2. An object value does not contain the token.
540+
3. A token is out of range of an array value.
541+
542+
Use unresolvedTokenIndex to retrieve the token index.
543+
*/
544+
UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0) const {
545+
static const Ch kIdString[] = { 'i', 'd', '\0' };
546+
static const ValueType kIdValue(kIdString, 2);
547+
UriType base = rootUri;
548+
RAPIDJSON_ASSERT(IsValid());
549+
ValueType* v = &root;
550+
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
551+
switch (v->GetType()) {
552+
case kObjectType:
553+
{
554+
// See if we have an id, and if so resolve with the current base
555+
typename ValueType::MemberIterator m = v->FindMember(kIdValue);
556+
if (m != v->MemberEnd() && (m->value).IsString()) {
557+
UriType here = UriType(m->value);
558+
here.Resolve(base);
559+
base = here;
560+
}
561+
m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
562+
if (m == v->MemberEnd())
563+
break;
564+
v = &m->value;
565+
}
566+
continue;
567+
case kArrayType:
568+
if (t->index == kPointerInvalidIndex || t->index >= v->Size())
569+
break;
570+
v = &((*v)[t->index]);
571+
continue;
572+
default:
573+
break;
574+
}
575+
576+
// Error: unresolved token
577+
if (unresolvedTokenIndex)
578+
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
579+
return UriType();
580+
}
581+
return base;
582+
}
583+
584+
UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0) const {
585+
return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex);
586+
}
587+
588+
523589
//!@name Query value
524590
//@{
525591

0 commit comments

Comments
 (0)