leptris 1.9.331.0 → 1.9.334.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/Rakefile +19 -1
- data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/arm64-darwin/libutf8proc.3.dylib +0 -0
- data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/x86_64-darwin/libutf8proc.3.dylib +0 -0
- data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/cdata.rb +4 -0
- data/lib/leptris/xml/comment.rb +4 -0
- data/lib/leptris/xml/descriptor.rb +55 -0
- data/lib/leptris/xml/entity_reference.rb +4 -0
- data/lib/leptris/xml/ffi.rb +25 -0
- data/lib/leptris/xml/node.rb +1 -0
- data/lib/leptris/xml/processing_instruction.rb +4 -0
- data/lib/leptris/xml/text.rb +4 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +65 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/include/leptris/descriptor.h +30 -0
- data/vendor-src/libleptris/src/include/leptris.h +5 -0
- data/vendor-src/libleptris/src/leptris/descriptor/plan.c +144 -0
- data/vendor-src/libleptris/src/leptris/dom/element_modify.c +7 -0
- data/vendor-src/libleptris/src/leptris/xsd/compile.c +241 -4
- data/vendor-src/libleptris/src/leptris/xsd/content_model.c +50 -0
- data/vendor-src/libleptris/src/leptris/xsd/validate.c +190 -8
- data/vendor-src/libleptris/src/leptris/xsd/xsd_internal.h +34 -0
- data/vendor-src/libleptris/test/abi/test_descriptor.cpp +95 -0
- data/vendor-src/libleptris/test/xsd/test_xsd_compile.cpp +380 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +2 -2
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* accumulate in the schema-owned error list — the RNG accessor
|
|
9
9
|
* pattern: validate returns 1/0, errors enumerate every miss.
|
|
10
10
|
*/
|
|
11
|
+
#include <ctype.h>
|
|
11
12
|
#include <stdio.h>
|
|
12
13
|
#include <stdlib.h>
|
|
13
14
|
#include <string.h>
|
|
@@ -50,6 +51,7 @@ static void verr(struct leptris_xsd_schema* s, const char* fmt,
|
|
|
50
51
|
const char* a, const char* b);
|
|
51
52
|
struct xsd_validator {
|
|
52
53
|
struct leptris_xsd_schema* s;
|
|
54
|
+
LeptrisDocument doc; /* the instance (assertion evaluation) */
|
|
53
55
|
struct xsd_error* errors;
|
|
54
56
|
struct xsd_error* tail;
|
|
55
57
|
size_t count;
|
|
@@ -86,16 +88,20 @@ static void verrf(struct xsd_validator* v, const char* what,
|
|
|
86
88
|
|
|
87
89
|
/* ---- lexical helpers ---------------------------------------------- */
|
|
88
90
|
|
|
91
|
+
static int simple_is_numeric(struct leptris_xsd_schema* s,
|
|
92
|
+
const XsdSimple* st);
|
|
93
|
+
|
|
89
94
|
static int text_valid(struct xsd_validator* v,
|
|
90
95
|
struct leptris_xsd_schema* s, const char* type,
|
|
91
96
|
const char* lexical, const char* what,
|
|
92
|
-
const char* name) {
|
|
97
|
+
const char* name, LeptrisElement elem) {
|
|
93
98
|
if (!type) return 1;
|
|
94
99
|
int r;
|
|
100
|
+
const XsdSimple* st = NULL;
|
|
95
101
|
if (strncmp(type, "xs:", 3) == 0)
|
|
96
102
|
r = xsd_builtin_valid(type, lexical);
|
|
97
103
|
else {
|
|
98
|
-
|
|
104
|
+
st = xsd_find_simple_pub(s, type);
|
|
99
105
|
if (!st) return 1; /* unresolved: accept */
|
|
100
106
|
r = xsd_simple_valid_chain(s, st, lexical);
|
|
101
107
|
}
|
|
@@ -103,6 +109,59 @@ static int text_valid(struct xsd_validator* v,
|
|
|
103
109
|
verrf(v, what, name, "lexical value does not match its type");
|
|
104
110
|
return 0;
|
|
105
111
|
}
|
|
112
|
+
/* XSD 1.1 xs:assertion facet (document validation only):
|
|
113
|
+
* $value binds the lexical — numeric lexicals bind bare,
|
|
114
|
+
* everything else as a string — and the context is the
|
|
115
|
+
* owning element. */
|
|
116
|
+
if (st && st->assertion && elem && v->doc) {
|
|
117
|
+
XsdSimple* mut = (XsdSimple*)st;
|
|
118
|
+
if (!mut->assertion_tried) {
|
|
119
|
+
mut->assertion_tried = 1;
|
|
120
|
+
if (xsd_schema_version_11(s)) {
|
|
121
|
+
/* eval_params binds DECLARED external variables —
|
|
122
|
+
* the test compiles under a $value declaration */
|
|
123
|
+
char wrapped[1024];
|
|
124
|
+
int w = snprintf(wrapped, sizeof(wrapped),
|
|
125
|
+
"declare variable $value external; %s",
|
|
126
|
+
mut->assertion);
|
|
127
|
+
if (w > 0 && (size_t)w < sizeof(wrapped))
|
|
128
|
+
mut->assertion_q =
|
|
129
|
+
leptris_xquery_parse(wrapped, (size_t)w);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (mut->assertion_q) {
|
|
133
|
+
char sel[256];
|
|
134
|
+
int numeric =
|
|
135
|
+
simple_is_numeric(s, st) && *lexical &&
|
|
136
|
+
strspn(lexical, "0123456789.+-eE") == strlen(lexical);
|
|
137
|
+
if (numeric)
|
|
138
|
+
snprintf(sel, sizeof(sel), "%s", lexical);
|
|
139
|
+
else {
|
|
140
|
+
size_t w = 0;
|
|
141
|
+
sel[w++] = '\'';
|
|
142
|
+
for (const char* p = lexical; *p && w < sizeof(sel) - 3;
|
|
143
|
+
p++) {
|
|
144
|
+
if (*p == '\'') sel[w++] = '\'';
|
|
145
|
+
sel[w++] = *p;
|
|
146
|
+
}
|
|
147
|
+
sel[w++] = '\'';
|
|
148
|
+
sel[w] = 0;
|
|
149
|
+
}
|
|
150
|
+
const char* names[1] = {"value"};
|
|
151
|
+
const char* sels[1] = {sel};
|
|
152
|
+
LeptrisXPathResult r2 = leptris_xquery_eval_params(
|
|
153
|
+
mut->assertion_q, v->doc, elem, names, sels, 1);
|
|
154
|
+
int ebv = 0;
|
|
155
|
+
if (r2) {
|
|
156
|
+
ebv = leptris_xpath_result_boolean(r2);
|
|
157
|
+
leptris_xpath_result_free(r2);
|
|
158
|
+
}
|
|
159
|
+
if (!ebv) {
|
|
160
|
+
verrf(v, what, name, "assertion failed");
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
106
165
|
return 1;
|
|
107
166
|
}
|
|
108
167
|
|
|
@@ -201,6 +260,59 @@ static void validate_children(struct xsd_validator* v,
|
|
|
201
260
|
}
|
|
202
261
|
}
|
|
203
262
|
|
|
263
|
+
/* $value binds typed: a numeric-derived simple type binds the
|
|
264
|
+
* lexical as a number literal, everything else as a string — the
|
|
265
|
+
* TYPE decides, not the lexical's shape ("5" under xs:string is
|
|
266
|
+
* the string '5'). */
|
|
267
|
+
static int numeric_builtin(const char* b) {
|
|
268
|
+
static const char* nums[] = {
|
|
269
|
+
"xs:integer", "xs:decimal", "xs:double", "xs:float",
|
|
270
|
+
"xs:int", "xs:long", "xs:short", "xs:byte",
|
|
271
|
+
"xs:nonNegativeInteger", "xs:positiveInteger",
|
|
272
|
+
"xs:negativeInteger", "xs:nonPositiveInteger",
|
|
273
|
+
"xs:unsignedLong", "xs:unsignedInt",
|
|
274
|
+
"xs:unsignedShort", "xs:unsignedByte", NULL};
|
|
275
|
+
for (int i = 0; nums[i]; i++)
|
|
276
|
+
if (strcmp(b, nums[i]) == 0) return 1;
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static int simple_is_numeric(struct leptris_xsd_schema* s,
|
|
281
|
+
const XsdSimple* st) {
|
|
282
|
+
for (int d = 0; st && d < 32; d++) {
|
|
283
|
+
if (!st->base) return 0;
|
|
284
|
+
if (strncmp(st->base, "xs:", 3) == 0)
|
|
285
|
+
return numeric_builtin(st->base);
|
|
286
|
+
st = xsd_find_simple_pub(s, st->base);
|
|
287
|
+
}
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* xs:anyAttribute grammar: ##any (or an absent attribute),
|
|
292
|
+
* ##other, ##targetNamespace, ##local, or a space-separated URI
|
|
293
|
+
* list. */
|
|
294
|
+
static int any_attr_matches(const char* grammar, const char* uri,
|
|
295
|
+
const char* target_ns) {
|
|
296
|
+
if (!grammar || strcmp(grammar, "##any") == 0) return 1;
|
|
297
|
+
if (strcmp(grammar, "##other") == 0)
|
|
298
|
+
return uri && target_ns && strcmp(uri, target_ns) != 0;
|
|
299
|
+
if (strcmp(grammar, "##targetNamespace") == 0)
|
|
300
|
+
return uri && target_ns && strcmp(uri, target_ns) == 0;
|
|
301
|
+
if (strcmp(grammar, "##local") == 0) return uri == NULL;
|
|
302
|
+
/* URI list */
|
|
303
|
+
const char* p = grammar;
|
|
304
|
+
while (*p) {
|
|
305
|
+
while (*p == ' ' || *p == '\t') p++;
|
|
306
|
+
if (!*p) break;
|
|
307
|
+
const char* start = p;
|
|
308
|
+
while (*p && *p != ' ' && *p != '\t') p++;
|
|
309
|
+
size_t len = (size_t)(p - start);
|
|
310
|
+
if (uri && strlen(uri) == len && strncmp(uri, start, len) == 0)
|
|
311
|
+
return 1;
|
|
312
|
+
}
|
|
313
|
+
return 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
204
316
|
static void validate_attributes(struct xsd_validator* v,
|
|
205
317
|
struct leptris_xsd_schema* s,
|
|
206
318
|
LeptrisElement elem,
|
|
@@ -231,11 +343,37 @@ static void validate_attributes(struct xsd_validator* v,
|
|
|
231
343
|
verrf(v, "attribute", a->name, "required but absent");
|
|
232
344
|
continue;
|
|
233
345
|
}
|
|
234
|
-
text_valid(v, s, a->type, val, "attribute", a->name);
|
|
346
|
+
text_valid(v, s, a->type, val, "attribute", a->name, elem);
|
|
235
347
|
if (a->fixed && strcmp(val, a->fixed) != 0)
|
|
236
348
|
verrf(v, "attribute", a->name,
|
|
237
349
|
"value does not match the fixed value");
|
|
238
350
|
}
|
|
351
|
+
/* strict: every instance attribute must be declared (or pass
|
|
352
|
+
* the type's xs:anyAttribute grammar). Namespace declarations
|
|
353
|
+
* are not attributes. */
|
|
354
|
+
for (LeptrisAttribute at = leptris_element_first_attribute(elem);
|
|
355
|
+
at; at = leptris_attribute_next(at)) {
|
|
356
|
+
const char* qn = leptris_attribute_get_name(at);
|
|
357
|
+
if (!qn || strncmp(qn, "xmlns", 5) == 0) continue;
|
|
358
|
+
const char* colon = strchr(qn, ':');
|
|
359
|
+
const char* local = colon ? colon + 1 : qn;
|
|
360
|
+
int declared = 0;
|
|
361
|
+
for (XsdAttrDecl* a = ta->attrs; a && !declared; a = a->next)
|
|
362
|
+
if (strcmp(a->name, local) == 0 ||
|
|
363
|
+
strcmp(a->name, qn) == 0)
|
|
364
|
+
declared = 1;
|
|
365
|
+
if (declared) continue;
|
|
366
|
+
if (ta->any_attr_ns) {
|
|
367
|
+
/* namespace of the attribute: engine-side attributes
|
|
368
|
+
* carry their uri through the expanded form */
|
|
369
|
+
const char* auri =
|
|
370
|
+
leptris_attribute_namespace_uri(at);
|
|
371
|
+
if (any_attr_matches(ta->any_attr_ns, auri,
|
|
372
|
+
xsd_target_ns(s)))
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
verrf(v, "attribute", local, "not declared (strict)");
|
|
376
|
+
}
|
|
239
377
|
}
|
|
240
378
|
|
|
241
379
|
static void validate_element(struct xsd_validator* v,
|
|
@@ -246,16 +384,39 @@ static void validate_element(struct xsd_validator* v,
|
|
|
246
384
|
leptris_element_expanded_name(elem, &local, &prefix, &uri);
|
|
247
385
|
if (!local) return;
|
|
248
386
|
const XsdElementDecl* d = xsd_find_element(s, local);
|
|
249
|
-
if (!d)
|
|
387
|
+
if (!d) {
|
|
388
|
+
/* strict: the instance uses an element the schema never
|
|
389
|
+
* declared (a local particle would have typed it) */
|
|
390
|
+
verrf(v, "element", local, "not declared (strict)");
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
250
393
|
|
|
251
|
-
|
|
394
|
+
/* XSD 1.1: the first alternative whose test passes types the
|
|
395
|
+
* element for this instance (context = the element). */
|
|
396
|
+
const char* eff_type = d->type;
|
|
397
|
+
for (XsdAlternative* alt = d->alternatives; alt; alt = alt->next) {
|
|
398
|
+
int ebv = 0;
|
|
399
|
+
if (alt->compiled && v->doc) {
|
|
400
|
+
LeptrisXPathResult r =
|
|
401
|
+
leptris_xquery_eval(alt->compiled, v->doc, elem);
|
|
402
|
+
if (r) {
|
|
403
|
+
ebv = leptris_xpath_result_boolean(r);
|
|
404
|
+
leptris_xpath_result_free(r);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (ebv) {
|
|
408
|
+
eff_type = alt->type;
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (!eff_type) return; /* anyType */
|
|
252
413
|
if (d->fixed) {
|
|
253
414
|
const char* text = leptris_element_text(elem);
|
|
254
415
|
if (text && *text && strcmp(text, d->fixed) != 0)
|
|
255
416
|
verrf(v, "element", local,
|
|
256
417
|
"content does not match the fixed value");
|
|
257
418
|
}
|
|
258
|
-
validate_local(v, s, elem, local,
|
|
419
|
+
validate_local(v, s, elem, local, eff_type);
|
|
259
420
|
}
|
|
260
421
|
|
|
261
422
|
/* Validate one element against a type name that comes from a
|
|
@@ -270,11 +431,27 @@ static void validate_local(struct xsd_validator* v,
|
|
|
270
431
|
if (ct) {
|
|
271
432
|
validate_attributes(v, s, elem, xsd_find_type_attrs(s, type));
|
|
272
433
|
validate_children(v, s, elem, ct);
|
|
434
|
+
/* XSD 1.1: the type's xs:assert list — context is the
|
|
435
|
+
* element; evaluation errors are failures */
|
|
436
|
+
for (XsdAssert* a = ct->asserts; a; a = a->next) {
|
|
437
|
+
int ebv = 0;
|
|
438
|
+
if (a->compiled && v->doc) {
|
|
439
|
+
LeptrisXPathResult r =
|
|
440
|
+
leptris_xquery_eval(a->compiled, v->doc, elem);
|
|
441
|
+
if (r) {
|
|
442
|
+
ebv = leptris_xpath_result_boolean(r);
|
|
443
|
+
leptris_xpath_result_free(r);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (!ebv)
|
|
447
|
+
verrf(v, "assertion", local, a->test ? a->test
|
|
448
|
+
: "(invalid)");
|
|
449
|
+
}
|
|
273
450
|
if (ct->text_type) {
|
|
274
451
|
const char* text = leptris_element_text(elem);
|
|
275
452
|
if (text && *text)
|
|
276
453
|
text_valid(v, s, ct->text_type, text, "element",
|
|
277
|
-
local);
|
|
454
|
+
local, elem);
|
|
278
455
|
}
|
|
279
456
|
return;
|
|
280
457
|
}
|
|
@@ -284,8 +461,12 @@ static void validate_local(struct xsd_validator* v,
|
|
|
284
461
|
xsd_find_simple_pub(s, type)) {
|
|
285
462
|
const char* text = leptris_element_text(elem);
|
|
286
463
|
if (text && *text)
|
|
287
|
-
text_valid(v, s, type, text, "element", local);
|
|
464
|
+
text_valid(v, s, type, text, "element", local, elem);
|
|
465
|
+
return;
|
|
288
466
|
}
|
|
467
|
+
/* neither complex nor simple nor builtin: the schema is
|
|
468
|
+
* incomplete — loud, never a silent accept (#1615 class) */
|
|
469
|
+
verrf(v, "element", local, "type not found in the schema");
|
|
289
470
|
}
|
|
290
471
|
|
|
291
472
|
/* ---- slice 6: identity constraints -------------------------------- */
|
|
@@ -509,6 +690,7 @@ void xsd_validator_free(struct xsd_validator* v) {
|
|
|
509
690
|
|
|
510
691
|
int xsd_validator_run(struct xsd_validator* v, LeptrisDocument doc) {
|
|
511
692
|
if (!v || !doc) return -1;
|
|
693
|
+
v->doc = doc; /* XSD 1.1: assertion evaluation context */
|
|
512
694
|
LeptrisElement root = leptris_document_root(doc);
|
|
513
695
|
if (!root) return -1;
|
|
514
696
|
validate_element(v, v->s, root, 0);
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
#include <stddef.h>
|
|
7
7
|
|
|
8
|
+
#include "../../include/leptris/xquery/xquery.h"
|
|
9
|
+
|
|
8
10
|
#ifdef __cplusplus
|
|
9
11
|
extern "C" {
|
|
10
12
|
#endif
|
|
@@ -57,6 +59,9 @@ typedef struct xsd_simple {
|
|
|
57
59
|
long total_digits;
|
|
58
60
|
long fraction_digits;
|
|
59
61
|
char* whitespace; /* "preserve" | "replace" | "collapse" */
|
|
62
|
+
char* assertion; /* XSD 1.1: the xs:assertion test text */
|
|
63
|
+
LeptrisXQuery assertion_q; /* compiled lazily at first use */
|
|
64
|
+
int assertion_tried; /* lazy-compile guard */
|
|
60
65
|
struct xsd_simple* next;
|
|
61
66
|
} XsdSimple;
|
|
62
67
|
|
|
@@ -65,6 +70,15 @@ typedef struct xsd_simple {
|
|
|
65
70
|
int xsd_simple_valid_chain(struct leptris_xsd_schema* s,
|
|
66
71
|
const XsdSimple* t, const char* v);
|
|
67
72
|
|
|
73
|
+
/* XSD 1.1 (#1075 tier 2): one xs:assert bound to a complexType —
|
|
74
|
+
* the compiled XPath 2 test plus its source text. Evaluation
|
|
75
|
+
* errors count as assertion failure. */
|
|
76
|
+
typedef struct xsd_assert {
|
|
77
|
+
char* test; /* the wire expression, for reporting */
|
|
78
|
+
LeptrisXQuery compiled; /* NULL when compilation failed */
|
|
79
|
+
struct xsd_assert* next;
|
|
80
|
+
} XsdAssert;
|
|
81
|
+
|
|
68
82
|
/* Content-model node: a particle (element ref / wildcard) or a
|
|
69
83
|
* group (sequence | choice | all). Owned by the schema; freed
|
|
70
84
|
* with the schema. */
|
|
@@ -88,8 +102,14 @@ typedef struct xsd_cm {
|
|
|
88
102
|
struct xsd_cm* first_child; /* group children list */
|
|
89
103
|
struct xsd_cm* next; /* sibling link within the parent group */
|
|
90
104
|
char* text_type; /* simpleContent wrapper: the text's type ref */
|
|
105
|
+
XsdAssert* asserts; /* XSD 1.1: the type's xs:assert list */
|
|
106
|
+
struct xsd_cm* open_any; /* XSD 1.1: xs:openContent wildcard */
|
|
107
|
+
int oc_mode; /* 0 none/unset, 1 suffix, 2 interleave */
|
|
108
|
+
int oc_owned; /* the wildcard node is this model's own */
|
|
91
109
|
} XsdCm;
|
|
92
110
|
|
|
111
|
+
|
|
112
|
+
|
|
93
113
|
/* A top-level xs:group definition: name + the model its refs
|
|
94
114
|
* splice in (the definition's single sequence/choice/all). */
|
|
95
115
|
typedef struct xsd_group_def {
|
|
@@ -98,15 +118,28 @@ typedef struct xsd_group_def {
|
|
|
98
118
|
struct xsd_group_def* next;
|
|
99
119
|
} XsdGroupDef;
|
|
100
120
|
|
|
121
|
+
/* XSD 1.1 (xs:schema @version="1.1") gates 1.1 enforcement. */
|
|
122
|
+
int xsd_schema_version_11(struct leptris_xsd_schema* s);
|
|
123
|
+
|
|
101
124
|
/* Group refs resolve through the schema at NFA-build time —
|
|
102
125
|
* forward references need no capture order. */
|
|
103
126
|
XsdGroupDef* xsd_find_group(struct leptris_xsd_schema* s,
|
|
104
127
|
const char* name);
|
|
105
128
|
|
|
129
|
+
/* XSD 1.1 (#1075 tier 2): one xs:alternative on an element
|
|
130
|
+
* declaration — the test plus the type it selects. */
|
|
131
|
+
typedef struct xsd_alternative {
|
|
132
|
+
char* test; /* wire text, for reporting */
|
|
133
|
+
LeptrisXQuery compiled; /* NULL when compilation failed */
|
|
134
|
+
char* type; /* the selected type name */
|
|
135
|
+
struct xsd_alternative* next;
|
|
136
|
+
} XsdAlternative;
|
|
137
|
+
|
|
106
138
|
/* A top-level xs:element declaration (slice 3: name + type ref). */
|
|
107
139
|
typedef struct xsd_element_decl {
|
|
108
140
|
char* name;
|
|
109
141
|
char* type; /* "xs:string"-style builtin or a local type name */
|
|
142
|
+
XsdAlternative* alternatives; /* XSD 1.1 conditional types */
|
|
110
143
|
char* fixed; /* fixed element content: text must string-equal it */
|
|
111
144
|
char* sub_head; /* substitutionGroup head (local name after ':') */
|
|
112
145
|
struct xsd_element_decl* next;
|
|
@@ -157,6 +190,7 @@ typedef struct xsd_attrgroup_def {
|
|
|
157
190
|
|
|
158
191
|
typedef struct xsd_type_attrs {
|
|
159
192
|
char* type_name;
|
|
193
|
+
char* any_attr_ns; /* xs:anyAttribute grammar (NULL = absent) */
|
|
160
194
|
XsdAttrDecl* attrs;
|
|
161
195
|
struct xsd_type_attrs* next;
|
|
162
196
|
} XsdTypeAttrs;
|
|
@@ -2131,3 +2131,98 @@ TEST(Plan1586, ExactUriRowStillWinsAndUnqualifiedStillBinds) {
|
|
|
2131
2131
|
leptris_document_free(doc);
|
|
2132
2132
|
leptris_plan_free(plan);
|
|
2133
2133
|
}
|
|
2134
|
+
|
|
2135
|
+
// ---- #408: native result builder + address attach -------------------
|
|
2136
|
+
namespace {
|
|
2137
|
+
|
|
2138
|
+
/* leptris_plan_result_build: a flat op program produces the same
|
|
2139
|
+
* standalone result tree a walk would — wrappers, ns bindings, kid
|
|
2140
|
+
* order — so leptris_plan_serialize serves standalone
|
|
2141
|
+
* serialization with no DOM mint on the host side. */
|
|
2142
|
+
TEST(Plan408, ResultBuildFeedsSerialize) {
|
|
2143
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
2144
|
+
leptris_child_plan kids[1] = {};
|
|
2145
|
+
kids[0].wire_name = "p";
|
|
2146
|
+
kids[0].kind = LEPTRIS_PLAN_KIND_SCALAR;
|
|
2147
|
+
kids[0].type_tag = 1;
|
|
2148
|
+
kids[0].child_plan_index = -1;
|
|
2149
|
+
leptris_element_plan plans[1] = {};
|
|
2150
|
+
plans[0].element_name = "b";
|
|
2151
|
+
plans[0].ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
2152
|
+
plans[0].child_count = 1;
|
|
2153
|
+
plans[0].child_plans = kids;
|
|
2154
|
+
leptris_plan_spec spec = {};
|
|
2155
|
+
spec.abi_version = leptris_plan_abi_version();
|
|
2156
|
+
spec.plan_count = 1;
|
|
2157
|
+
spec.plans = plans;
|
|
2158
|
+
LeptrisPlan plan = leptris_plan_build(&spec, &st);
|
|
2159
|
+
ASSERT_NE(plan, nullptr);
|
|
2160
|
+
|
|
2161
|
+
/* a SCALAR op IS the row's value (name and binding come from
|
|
2162
|
+
* the plan row) — no ELEMENT wrapper needed for scalar rows */
|
|
2163
|
+
leptris_plan_row_op ops[] = {
|
|
2164
|
+
{LEPTRIS_PLAN_OP_ELEMENT, 0, UINT32_MAX, NULL, NULL, 0},
|
|
2165
|
+
{LEPTRIS_PLAN_OP_ATTR, 0, UINT32_MAX, "id", "7", 1},
|
|
2166
|
+
{LEPTRIS_PLAN_OP_SCALAR, 0, 0, NULL, "first", 5},
|
|
2167
|
+
{LEPTRIS_PLAN_OP_END, 0, UINT32_MAX, NULL, NULL, 0},
|
|
2168
|
+
};
|
|
2169
|
+
LeptrisPlanResult r =
|
|
2170
|
+
leptris_plan_result_build(plan, ops, 4, &st);
|
|
2171
|
+
ASSERT_NE(r, nullptr);
|
|
2172
|
+
char* out = leptris_plan_serialize(plan, r, &st);
|
|
2173
|
+
ASSERT_NE(out, nullptr);
|
|
2174
|
+
EXPECT_STREQ(out, "<b id=\"7\"><p>first</p></b>");
|
|
2175
|
+
leptris_free_string(out);
|
|
2176
|
+
leptris_plan_result_free(r);
|
|
2177
|
+
leptris_plan_free(plan);
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
TEST(Plan408, ResultBuildRejectsBadPrograms) {
|
|
2181
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
2182
|
+
leptris_element_plan plans[1] = {};
|
|
2183
|
+
plans[0].element_name = "b";
|
|
2184
|
+
plans[0].ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
2185
|
+
leptris_plan_spec spec = {};
|
|
2186
|
+
spec.abi_version = leptris_plan_abi_version();
|
|
2187
|
+
spec.plan_count = 1;
|
|
2188
|
+
spec.plans = plans;
|
|
2189
|
+
LeptrisPlan plan = leptris_plan_build(&spec, &st);
|
|
2190
|
+
ASSERT_NE(plan, nullptr);
|
|
2191
|
+
|
|
2192
|
+
/* END without an open element */
|
|
2193
|
+
leptris_plan_row_op bad1[] = {
|
|
2194
|
+
{LEPTRIS_PLAN_OP_END, 0, UINT32_MAX, NULL, NULL, 0}};
|
|
2195
|
+
EXPECT_EQ(leptris_plan_result_build(plan, bad1, 1, &st), nullptr);
|
|
2196
|
+
/* unclosed element */
|
|
2197
|
+
leptris_plan_row_op bad2[] = {
|
|
2198
|
+
{LEPTRIS_PLAN_OP_ELEMENT, 0, UINT32_MAX, NULL, NULL, 0}};
|
|
2199
|
+
EXPECT_EQ(leptris_plan_result_build(plan, bad2, 1, &st), nullptr);
|
|
2200
|
+
/* NULL/empty args */
|
|
2201
|
+
EXPECT_EQ(leptris_plan_result_build(NULL, bad2, 1, &st), nullptr);
|
|
2202
|
+
EXPECT_EQ(leptris_plan_result_build(plan, NULL, 0, &st), nullptr);
|
|
2203
|
+
leptris_plan_free(plan);
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
/* leptris_element_add_child_addr: attach by raw addresses — the
|
|
2207
|
+
* binding's per-node FFI::Pointer mint (#408 ask 1) disappears. */
|
|
2208
|
+
TEST(Plan408, AddChildByAddress) {
|
|
2209
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
2210
|
+
LeptrisDocument doc = leptris_parse_string("<r/>", 4, &st);
|
|
2211
|
+
ASSERT_NE(doc, nullptr);
|
|
2212
|
+
LeptrisElement parent = leptris_document_root(doc);
|
|
2213
|
+
LeptrisElement child = leptris_element_create(doc, "c");
|
|
2214
|
+
ASSERT_NE(child, nullptr);
|
|
2215
|
+
EXPECT_EQ(leptris_element_add_child_addr(
|
|
2216
|
+
(uintptr_t)parent, (uintptr_t)child),
|
|
2217
|
+
LEPTRIS_OK);
|
|
2218
|
+
EXPECT_EQ(leptris_element_child_count(parent), 1u);
|
|
2219
|
+
LeptrisElement got = leptris_element_first_child_any(parent);
|
|
2220
|
+
ASSERT_NE(got, nullptr);
|
|
2221
|
+
EXPECT_STREQ(leptris_element_name(got), "c");
|
|
2222
|
+
/* NULL-shaped addresses are clean errors */
|
|
2223
|
+
EXPECT_NE(leptris_element_add_child_addr(0, (uintptr_t)child),
|
|
2224
|
+
LEPTRIS_OK);
|
|
2225
|
+
leptris_document_free(doc);
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
} // namespace
|