rj_schema 0.2.5 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
  3. data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
  4. data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
  5. data/ext/rj_schema/rapidjson/bin/unittestschema/address.json +139 -0
  6. data/ext/rj_schema/rapidjson/bin/unittestschema/allOf_address.json +7 -0
  7. data/ext/rj_schema/rapidjson/bin/unittestschema/anyOf_address.json +7 -0
  8. data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
  9. data/ext/rj_schema/rapidjson/bin/unittestschema/oneOf_address.json +7 -0
  10. data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
  11. data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
  12. data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
  13. data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +120 -0
  14. data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
  15. data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +464 -56
  16. data/ext/rj_schema/rapidjson/include/rapidjson/cursorstreamwrapper.h +1 -1
  17. data/ext/rj_schema/rapidjson/include/rapidjson/document.h +367 -72
  18. data/ext/rj_schema/rapidjson/include/rapidjson/encodedstream.h +1 -1
  19. data/ext/rj_schema/rapidjson/include/rapidjson/encodings.h +1 -1
  20. data/ext/rj_schema/rapidjson/include/rapidjson/error/en.h +49 -1
  21. data/ext/rj_schema/rapidjson/include/rapidjson/error/error.h +56 -1
  22. data/ext/rj_schema/rapidjson/include/rapidjson/filereadstream.h +1 -1
  23. data/ext/rj_schema/rapidjson/include/rapidjson/filewritestream.h +1 -1
  24. data/ext/rj_schema/rapidjson/include/rapidjson/fwd.h +1 -1
  25. data/ext/rj_schema/rapidjson/include/rapidjson/internal/biginteger.h +1 -1
  26. data/ext/rj_schema/rapidjson/include/rapidjson/internal/clzll.h +4 -4
  27. data/ext/rj_schema/rapidjson/include/rapidjson/internal/diyfp.h +1 -1
  28. data/ext/rj_schema/rapidjson/include/rapidjson/internal/dtoa.h +1 -1
  29. data/ext/rj_schema/rapidjson/include/rapidjson/internal/ieee754.h +1 -1
  30. data/ext/rj_schema/rapidjson/include/rapidjson/internal/itoa.h +1 -1
  31. data/ext/rj_schema/rapidjson/include/rapidjson/internal/meta.h +1 -1
  32. data/ext/rj_schema/rapidjson/include/rapidjson/internal/pow10.h +1 -1
  33. data/ext/rj_schema/rapidjson/include/rapidjson/internal/regex.h +1 -1
  34. data/ext/rj_schema/rapidjson/include/rapidjson/internal/stack.h +1 -1
  35. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +15 -1
  36. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strtod.h +1 -1
  37. data/ext/rj_schema/rapidjson/include/rapidjson/internal/swap.h +1 -1
  38. data/ext/rj_schema/rapidjson/include/rapidjson/istreamwrapper.h +1 -1
  39. data/ext/rj_schema/rapidjson/include/rapidjson/memorybuffer.h +1 -1
  40. data/ext/rj_schema/rapidjson/include/rapidjson/memorystream.h +1 -1
  41. data/ext/rj_schema/rapidjson/include/rapidjson/ostreamwrapper.h +1 -1
  42. data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +69 -2
  43. data/ext/rj_schema/rapidjson/include/rapidjson/prettywriter.h +1 -1
  44. data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +77 -12
  45. data/ext/rj_schema/rapidjson/include/rapidjson/reader.h +17 -9
  46. data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +558 -259
  47. data/ext/rj_schema/rapidjson/include/rapidjson/stream.h +1 -1
  48. data/ext/rj_schema/rapidjson/include/rapidjson/stringbuffer.h +1 -1
  49. data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
  50. data/ext/rj_schema/rapidjson/include/rapidjson/writer.h +3 -3
  51. data/ext/rj_schema/rapidjson/readme.md +3 -3
  52. data/ext/rj_schema/rapidjson/readme.zh-cn.md +2 -2
  53. data/ext/rj_schema/rapidjson/test/perftest/misctest.cpp +1 -1
  54. data/ext/rj_schema/rapidjson/test/perftest/perftest.cpp +1 -1
  55. data/ext/rj_schema/rapidjson/test/perftest/perftest.h +6 -5
  56. data/ext/rj_schema/rapidjson/test/perftest/platformtest.cpp +1 -1
  57. data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +21 -3
  58. data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +3 -0
  59. data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +194 -2
  60. data/ext/rj_schema/rapidjson/test/unittest/bigintegertest.cpp +1 -1
  61. data/ext/rj_schema/rapidjson/test/unittest/clzlltest.cpp +34 -0
  62. data/ext/rj_schema/rapidjson/test/unittest/cursorstreamwrappertest.cpp +1 -1
  63. data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +3 -1
  64. data/ext/rj_schema/rapidjson/test/unittest/dtoatest.cpp +1 -1
  65. data/ext/rj_schema/rapidjson/test/unittest/encodedstreamtest.cpp +1 -1
  66. data/ext/rj_schema/rapidjson/test/unittest/encodingstest.cpp +1 -1
  67. data/ext/rj_schema/rapidjson/test/unittest/filestreamtest.cpp +1 -1
  68. data/ext/rj_schema/rapidjson/test/unittest/fwdtest.cpp +1 -1
  69. data/ext/rj_schema/rapidjson/test/unittest/istreamwrappertest.cpp +1 -1
  70. data/ext/rj_schema/rapidjson/test/unittest/itoatest.cpp +1 -1
  71. data/ext/rj_schema/rapidjson/test/unittest/jsoncheckertest.cpp +1 -1
  72. data/ext/rj_schema/rapidjson/test/unittest/namespacetest.cpp +1 -1
  73. data/ext/rj_schema/rapidjson/test/unittest/ostreamwrappertest.cpp +1 -1
  74. data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
  75. data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +95 -3
  76. data/ext/rj_schema/rapidjson/test/unittest/prettywritertest.cpp +1 -1
  77. data/ext/rj_schema/rapidjson/test/unittest/readertest.cpp +4 -1
  78. data/ext/rj_schema/rapidjson/test/unittest/regextest.cpp +1 -1
  79. data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +961 -81
  80. data/ext/rj_schema/rapidjson/test/unittest/simdtest.cpp +1 -1
  81. data/ext/rj_schema/rapidjson/test/unittest/strfunctest.cpp +1 -1
  82. data/ext/rj_schema/rapidjson/test/unittest/stringbuffertest.cpp +1 -1
  83. data/ext/rj_schema/rapidjson/test/unittest/strtodtest.cpp +1 -1
  84. data/ext/rj_schema/rapidjson/test/unittest/unittest.cpp +1 -1
  85. data/ext/rj_schema/rapidjson/test/unittest/unittest.h +1 -1
  86. data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
  87. data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +13 -3
  88. data/ext/rj_schema/rapidjson/test/unittest/writertest.cpp +1 -1
  89. data/ext/rj_schema/rj_schema.cpp +162 -18
  90. data/lib/rj_schema.rb +1 -1
  91. metadata +14 -3
@@ -0,0 +1,139 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "version": {
5
+ "$ref": "#/definitions/decimal_type"
6
+ },
7
+ "address": {
8
+ "$ref": "#/definitions/address_type"
9
+ },
10
+ "phones": {
11
+ "type": "array",
12
+ "minItems": 1,
13
+ "maxItems": 2,
14
+ "uniqueItems": true,
15
+ "items": {
16
+ "$ref": "#/definitions/phone_type"
17
+ }
18
+ },
19
+ "names": {
20
+ "type": "array",
21
+ "items": [
22
+ { "type": "string" },
23
+ { "type": "string" }
24
+ ],
25
+ "additionalItems": false
26
+ },
27
+ "extra": {
28
+ "type": "object",
29
+ "patternProperties": {
30
+ "^S_": { "type": "string" }
31
+ }
32
+ },
33
+ "gender": {
34
+ "type": "string",
35
+ "enum": ["M", "F"]
36
+ }
37
+ },
38
+ "additionalProperties": false,
39
+ "dependencies": {
40
+ "address": [ "version" ],
41
+ "names": {
42
+ "properties": {
43
+ "version": { "$ref": "#/definitions/decimal_type" }
44
+ },
45
+ "required": ["version"]
46
+ }
47
+ },
48
+ "definitions": {
49
+ "address_type": {
50
+ "type": "object",
51
+ "properties": {
52
+ "number": {
53
+ "$ref": "#/definitions/positiveInt_type"
54
+ },
55
+ "street1": {
56
+ "type": "string"
57
+ },
58
+ "street2": {
59
+ "type": ["string", "null"]
60
+ },
61
+ "street3": {
62
+ "not": { "type": ["boolean", "number", ",integer", "object", "null"] }
63
+ },
64
+ "city": {
65
+ "type": "string",
66
+ "maxLength": 10,
67
+ "minLength": 4
68
+ },
69
+ "area": {
70
+ "oneOf": [
71
+ { "$ref": "#/definitions/county_type" },
72
+ { "$ref": "#/definitions/province_type" }
73
+ ]
74
+ },
75
+ "country": {
76
+ "allOf": [
77
+ { "$ref": "#/definitions/country_type" }
78
+ ]
79
+ },
80
+ "postcode": {
81
+ "anyOf": [
82
+ { "type": "string", "pattern": "^[A-Z]{2}[0-9]{1,2} [0-9][A-Z]{2}$" },
83
+ { "type": "string", "pattern": "^[0-9]{5}$" }
84
+ ]
85
+ }
86
+ },
87
+ "minProperties": 7,
88
+ "required": [
89
+ "number",
90
+ "street1",
91
+ "city"
92
+ ]
93
+ },
94
+ "country_type": {
95
+ "type": "string",
96
+ "enum": ["UK", "Canada"]
97
+ },
98
+ "county_type": {
99
+ "type": "string",
100
+ "enum": ["Sussex", "Surrey", "Kent"]
101
+ },
102
+ "province_type": {
103
+ "type": "string",
104
+ "enum": ["Quebec", "BC", "Alberta"]
105
+ },
106
+ "date_type": {
107
+ "pattern": "^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?$",
108
+ "type": "string"
109
+ },
110
+ "positiveInt_type": {
111
+ "minimum": 0,
112
+ "exclusiveMinimum": true,
113
+ "maximum": 100,
114
+ "exclusiveMaximum": true,
115
+ "type": "integer"
116
+ },
117
+ "decimal_type": {
118
+ "multipleOf": 1.0,
119
+ "type": "number"
120
+ },
121
+ "time_type": {
122
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?$",
123
+ "type": "string"
124
+ },
125
+ "unsignedInt_type": {
126
+ "type": "integer",
127
+ "minimum": 0,
128
+ "maximum": 99999
129
+ },
130
+ "phone_type": {
131
+ "pattern": "^[0-9]*-[0-9]*",
132
+ "type": "string"
133
+ },
134
+ "url_type": {
135
+ "pattern": "^\\S*$",
136
+ "type": "string"
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "allOf": [
3
+ {
4
+ "$ref": "http://localhost:1234/address.json#"
5
+ }
6
+ ]
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "anyOf": [
3
+ {
4
+ "$ref": "http://localhost:1234/address.json#"
5
+ }
6
+ ]
7
+ }
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "oneOf": [
3
+ {
4
+ "$ref": "http://localhost:1234/address.json#"
5
+ }
6
+ ]
7
+ }
@@ -1,6 +1,6 @@
1
1
  # Stream
2
2
 
3
- In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we first show how to use streams provided. And then see how to create a custom stream.
3
+ In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we'll first show you how to use provided streams. And then see how to create a custom stream.
4
4
 
5
5
  [TOC]
6
6
 
@@ -51,7 +51,7 @@ d.Accept(writer);
51
51
  const char* output = buffer.GetString();
52
52
  ~~~~~~~~~~
53
53
 
54
- When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity.
54
+ When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and an initial capacity.
55
55
 
56
56
  ~~~~~~~~~~cpp
57
57
  StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
@@ -89,7 +89,7 @@ d.ParseStream(is);
89
89
  fclose(fp);
90
90
  ~~~~~~~~~~
91
91
 
92
- Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon.
92
+ Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. We will discuss more about this later in this tutorial.
93
93
 
94
94
  Apart from reading file, user can also use `FileReadStream` to read `stdin`.
95
95
 
@@ -119,11 +119,11 @@ d.Accept(writer);
119
119
  fclose(fp);
120
120
  ~~~~~~~~~~
121
121
 
122
- It can also directs the output to `stdout`.
122
+ It can also redirect the output to `stdout`.
123
123
 
124
124
  # iostream Wrapper {#iostreamWrapper}
125
125
 
126
- Due to users' requests, RapidJSON provided official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
126
+ Due to users' requests, RapidJSON also provides official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
127
127
 
128
128
  ## IStreamWrapper {#IStreamWrapper}
129
129
 
@@ -181,7 +181,7 @@ As mentioned above, UTF-8 byte streams can be read directly. However, UTF-16 and
181
181
 
182
182
  Besides, it also need to handle [byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark). When reading from a byte stream, it is needed to detect or just consume the BOM if exists. When writing to a byte stream, it can optionally write BOM.
183
183
 
184
- If the encoding of stream is known in compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
184
+ If the encoding of stream is known during compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
185
185
 
186
186
  Note that, these encoded streams can be applied to streams other than file. For example, you may have a file in memory, or a custom byte stream, be wrapped in encoded streams.
187
187
 
@@ -231,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
231
231
  typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
232
232
  OutputStream eos(bos, true); // Write BOM
233
233
 
234
- Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
234
+ Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
235
235
  d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory
236
236
 
237
237
  fclose(fp);
@@ -231,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
231
231
  typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
232
232
  OutputStream eos(bos, true); // 写入 BOM
233
233
 
234
- Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
234
+ Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
235
235
  d.Accept(writer); // 这里从内存的 UTF-8 生成 UTF32-LE 文件
236
236
 
237
237
  fclose(fp);
@@ -12,7 +12,7 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t
12
12
 
13
13
  # Query Value {#QueryValue}
14
14
 
15
- In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
15
+ In this section, we will use excerpt from `example/tutorial/tutorial.cpp`.
16
16
 
17
17
  Assume we have the following JSON stored in a C string (`const char* json`):
18
18
  ~~~~~~~~~~js
@@ -85,7 +85,7 @@ assert(document["i"].IsNumber());
85
85
  // In this case, IsUint()/IsInt64()/IsUint64() also return true.
86
86
  assert(document["i"].IsInt());
87
87
  printf("i = %d\n", document["i"].GetInt());
88
- // Alternative (int)document["i"]
88
+ // Alternatively (int)document["i"]
89
89
 
90
90
  assert(document["pi"].IsNumber());
91
91
  assert(document["pi"].IsDouble());
@@ -113,7 +113,7 @@ a[2] = 3
113
113
  a[3] = 4
114
114
  ~~~~~~~~~~
115
115
 
116
- Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
116
+ Note that, RapidJSON does not automatically convert values between JSON types. For example, if a value is a string, it is invalid to call `GetInt()`. In debug mode it will fail on assertion. In release mode, the behavior is undefined.
117
117
 
118
118
  In the following sections we discuss details about querying individual types.
119
119
 
@@ -168,9 +168,9 @@ Type of member pi is Number
168
168
  Type of member a is Array
169
169
  ~~~~~~~~~~
170
170
 
171
- Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
171
+ Note that, when `operator[](const char*)` cannot find the member, it will fail on assertion.
172
172
 
173
- If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
173
+ If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of a member and obtain its value at once:
174
174
 
175
175
  ~~~~~~~~~~cpp
176
176
  Value::ConstMemberIterator itr = document.FindMember("hello");
@@ -221,18 +221,18 @@ When obtaining the numeric values, `GetDouble()` will convert internal integer r
221
221
 
222
222
  ## Query String {#QueryString}
223
223
 
224
- In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.
224
+ In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why:
225
225
 
226
- According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
226
+ According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats `\0` as the terminator symbol.
227
227
 
228
- To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
228
+ To conform with RFC 4627, RapidJSON supports string containing `U+0000` character. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
229
229
 
230
- For example, after parsing a the following JSON to `Document d`:
230
+ For example, after parsing the following JSON to `Document d`:
231
231
 
232
232
  ~~~~~~~~~~js
233
233
  { "s" : "a\u0000b" }
234
234
  ~~~~~~~~~~
235
- The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
235
+ The correct length of the string `"a\u0000b"` is 3, as returned by `GetStringLength()`. But `strlen()` returns 1.
236
236
 
237
237
  `GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
238
238
 
@@ -246,7 +246,7 @@ which accepts the length of string as parameter. This constructor supports stori
246
246
 
247
247
  ## Comparing values
248
248
 
249
- You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.
249
+ You can use `==` and `!=` to compare values. Two values are equal if and only if they have same type and contents. You can also compare values with primitive types. Here is an example:
250
250
 
251
251
  ~~~~~~~~~~cpp
252
252
  if (document["hello"] == document["n"]) /*...*/; // Compare values
@@ -264,7 +264,7 @@ Note that, currently if an object contains duplicated named member, comparing eq
264
264
  There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.
265
265
 
266
266
  ## Change Value Type {#ChangeValueType}
267
- When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
267
+ When creating a `Value` or `Document` by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
268
268
 
269
269
  ~~~~~~~~~~cpp
270
270
  Document d; // Null
@@ -285,7 +285,7 @@ Value u(123u); // calls Value(unsigned)
285
285
  Value d(1.5); // calls Value(double)
286
286
  ~~~~~~~~~~
287
287
 
288
- To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:
288
+ To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one call:
289
289
 
290
290
  ~~~~~~~~~~cpp
291
291
  Value o(kObjectType);
@@ -299,7 +299,7 @@ A very special decision during design of RapidJSON is that, assignment of value
299
299
  ~~~~~~~~~~cpp
300
300
  Value a(123);
301
301
  Value b(456);
302
- b = a; // a becomes a Null value, b becomes number 123.
302
+ a = b; // b becomes a Null value, a becomes number 456.
303
303
  ~~~~~~~~~~
304
304
 
305
305
  ![Assignment with move semantics.](diagram/move1.png)
@@ -367,7 +367,7 @@ RapidJSON provides two strategies for storing string.
367
367
 
368
368
  Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing a string literal, and for in-situ parsing which will be mentioned in the DOM section.
369
369
 
370
- To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
370
+ To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing an allocator (or Document) pointer per Value.
371
371
 
372
372
  Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
373
373
 
@@ -2,14 +2,131 @@
2
2
 
3
3
  // The example validates JSON text from stdin with a JSON schema specified in the argument.
4
4
 
5
+ #define RAPIDJSON_HAS_STDSTRING 1
6
+
5
7
  #include "rapidjson/error/en.h"
6
8
  #include "rapidjson/filereadstream.h"
7
9
  #include "rapidjson/schema.h"
8
10
  #include "rapidjson/stringbuffer.h"
9
11
  #include "rapidjson/prettywriter.h"
12
+ #include <string>
13
+ #include <iostream>
14
+ #include <sstream>
10
15
 
11
16
  using namespace rapidjson;
12
17
 
18
+ typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
19
+
20
+ // Forward ref
21
+ static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
22
+
23
+ // Convert GenericValue to std::string
24
+ static std::string GetString(const ValueType& val) {
25
+ std::ostringstream s;
26
+ if (val.IsString())
27
+ s << val.GetString();
28
+ else if (val.IsDouble())
29
+ s << val.GetDouble();
30
+ else if (val.IsUint())
31
+ s << val.GetUint();
32
+ else if (val.IsInt())
33
+ s << val.GetInt();
34
+ else if (val.IsUint64())
35
+ s << val.GetUint64();
36
+ else if (val.IsInt64())
37
+ s << val.GetInt64();
38
+ else if (val.IsBool() && val.GetBool())
39
+ s << "true";
40
+ else if (val.IsBool())
41
+ s << "false";
42
+ else if (val.IsFloat())
43
+ s << val.GetFloat();
44
+ return s.str();}
45
+
46
+ // Create the error message for a named error
47
+ // The error object can either be empty or contain at least member properties:
48
+ // {"errorCode": <code>, "instanceRef": "<pointer>", "schemaRef": "<pointer>" }
49
+ // Additional properties may be present for use as inserts.
50
+ // An "errors" property may be present if there are child errors.
51
+ static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
52
+ if (!error.ObjectEmpty()) {
53
+ // Get error code and look up error message text (English)
54
+ int code = error["errorCode"].GetInt();
55
+ std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
56
+ // For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
57
+ // So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
58
+ for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin();
59
+ insertsItr != error.MemberEnd(); ++insertsItr) {
60
+ std::string insertName("%");
61
+ insertName += insertsItr->name.GetString(); // eg "%actual"
62
+ size_t insertPos = message.find(insertName);
63
+ if (insertPos != std::string::npos) {
64
+ std::string insertString("");
65
+ const ValueType &insert = insertsItr->value;
66
+ if (insert.IsArray()) {
67
+ // Member is an array so create comma-separated list of items for the insert string
68
+ for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
69
+ if (itemsItr != insert.Begin()) insertString += ",";
70
+ insertString += GetString(*itemsItr);
71
+ }
72
+ } else {
73
+ insertString += GetString(insert);
74
+ }
75
+ message.replace(insertPos, insertName.length(), insertString);
76
+ }
77
+ }
78
+ // Output error message, references, context
79
+ std::string indent(depth * 2, ' ');
80
+ std::cout << indent << "Error Name: " << errorName << std::endl;
81
+ std::cout << indent << "Message: " << message.c_str() << std::endl;
82
+ std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
83
+ std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
84
+ if (depth > 0) std::cout << indent << "Context: " << context << std::endl;
85
+ std::cout << std::endl;
86
+
87
+ // If child errors exist, apply the process recursively to each error structure.
88
+ // This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
89
+ if (error.HasMember("errors")) {
90
+ depth++;
91
+ const ValueType &childErrors = error["errors"];
92
+ if (childErrors.IsArray()) {
93
+ // Array - each item is an error structure - example
94
+ // "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
95
+ for (ValueType::ConstValueIterator errorsItr = childErrors.Begin();
96
+ errorsItr != childErrors.End(); ++errorsItr) {
97
+ CreateErrorMessages(*errorsItr, depth, errorName);
98
+ }
99
+ } else if (childErrors.IsObject()) {
100
+ // Object - each member is an error structure - example
101
+ // "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
102
+ for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin();
103
+ propsItr != childErrors.MemberEnd(); ++propsItr) {
104
+ CreateErrorMessages(propsItr->value, depth, errorName);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ // Create error message for all errors in an error structure
112
+ // Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
113
+ static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
114
+ // Each member property contains one or more errors of a given type
115
+ for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
116
+ const char* errorName = errorTypeItr->name.GetString();
117
+ const ValueType& errorContent = errorTypeItr->value;
118
+ if (errorContent.IsArray()) {
119
+ // Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
120
+ for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
121
+ HandleError(errorName, *contentItr, depth, context);
122
+ }
123
+ } else if (errorContent.IsObject()) {
124
+ // Member is an object which is a single error - eg "type": {"errorCode": ... }
125
+ HandleError(errorName, errorContent, depth, context);
126
+ }
127
+ }
128
+ }
129
+
13
130
  int main(int argc, char *argv[]) {
14
131
  if (argc != 2) {
15
132
  fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
@@ -65,6 +182,8 @@ int main(int argc, char *argv[]) {
65
182
  validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
66
183
  fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
67
184
  fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
185
+ fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
186
+ fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
68
187
  sb.Clear();
69
188
  validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
70
189
  fprintf(stderr, "Invalid document: %s\n", sb.GetString());
@@ -73,6 +192,7 @@ int main(int argc, char *argv[]) {
73
192
  PrettyWriter<StringBuffer> w(sb);
74
193
  validator.GetError().Accept(w);
75
194
  fprintf(stderr, "Error report:\n%s\n", sb.GetString());
195
+ CreateErrorMessages(validator.GetError());
76
196
  return EXIT_FAILURE;
77
197
  }
78
198
  }