leptris 1.9.331.0-aarch64-linux → 1.9.333.0-aarch64-linux
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/Rakefile +1 -1
- 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/entity_reference.rb +4 -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/lib/libleptris.so +0 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +36 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/leptris/xsd/compile.c +209 -0
- data/vendor-src/libleptris/src/leptris/xsd/content_model.c +15 -0
- data/vendor-src/libleptris/src/leptris/xsd/validate.c +100 -7
- data/vendor-src/libleptris/src/leptris/xsd/xsd_internal.h +33 -0
- data/vendor-src/libleptris/test/xsd/test_xsd_compile.cpp +277 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 98ae1dcb70070a749f8df3f2454bf8d51e020fe5c222f36ad994798dbf9df672
|
|
4
|
+
data.tar.gz: 1a034cda5efbd4a6998e43a30b203a4884be9a7623a4a58f324b13766012fe3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0cb18a00e9d4833788336925a4807d27b455d994f6025ae0b90a06a7932669314c5f26550e3201ad30716d92ed7ee8c0e18fac70fd1e15090a846670f8afb93c
|
|
7
|
+
data.tar.gz: b700e9de1094f955049cfef2263b890d25ef81c54b369289e92609c29df46739562b35b5d37a81bb51b1ce81c18db403c212963ee79312d41292ee3fd1b5e20e
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.333"
|
|
12
12
|
# Vendored alongside libleptris for fn:normalize-unicode (TODO
|
|
13
13
|
# .restructure/20): built per platform with a RELOCATABLE @rpath
|
|
14
14
|
# install name, loaded by ffi.rb before libleptris so the
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/cdata.rb
CHANGED
data/lib/leptris/xml/comment.rb
CHANGED
data/lib/leptris/xml/node.rb
CHANGED
|
@@ -50,6 +50,10 @@ class Leptris::XML::ProcessingInstruction < Leptris::XML::Node
|
|
|
50
50
|
new_data
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def to_s
|
|
54
|
+
content.to_s.empty? ? "<?#{name}?>" : "<?#{name} #{content}?>"
|
|
55
|
+
end
|
|
56
|
+
|
|
53
57
|
# Document-level PIs have no tree parent for leptris_node_unlink
|
|
54
58
|
# — route through the document-level removal (libleptris 1.9.9,
|
|
55
59
|
# #612), identity-matched by index so the right same-target PI
|
data/lib/leptris/xml/text.rb
CHANGED
data/lib/libleptris.so
CHANGED
|
Binary file
|
data/vendor-src/README.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.333] - 2026-10-10
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Regression pin: union `memberTypes` + inline anonymous members
|
|
8
|
+
(#1615, PR #1618).** The reported over-acceptance was not
|
|
9
|
+
reproducible on any engine artifact (main, the v1.9.331 tag,
|
|
10
|
+
every published gem binary — including through the full Ruby
|
|
11
|
+
binding path). The exact schema now asserts in CI through both
|
|
12
|
+
`leptris_xsd_simple_valid` and instance validation, so the
|
|
13
|
+
mixed-member semantics are verifiable binary-independent of any
|
|
14
|
+
binding environment.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [1.9.332] - 2026-10-09
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **XSD 1.1 — tier 2 (#1075, PR #1616).** Gated on
|
|
22
|
+
`xs:schema @version="1.1"`: `xs:assert` on complexTypes (direct
|
|
23
|
+
and derivation-nested; compiled once, evaluated per instance
|
|
24
|
+
through the engine's XPath 2 lane; evaluation errors are
|
|
25
|
+
failures); `xs:assertion` on simpleTypes (`$value` binds the
|
|
26
|
+
lexical, element context); `xs:openContent` interleave/suffix
|
|
27
|
+
(wildcard self-loops at the Thompson NFA's junction states;
|
|
28
|
+
`xs:defaultOpenContent` schema-wide with `appliesToEmpty`) and
|
|
29
|
+
`xs:alternative` conditional type assignment (first passing
|
|
30
|
+
test types the instance, declared type as fallback). Ten
|
|
31
|
+
red-first specs; ctest 1951/1951; 1.0 schemas unaffected.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- free the defaultOpenContent wildcard with the schema (xsd)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
3
39
|
## [1.9.331] - 2026-10-09
|
|
4
40
|
|
|
5
41
|
### Fixed
|
|
@@ -36,11 +36,14 @@ struct leptris_xsd_schema {
|
|
|
36
36
|
XsdElementDecl* elements;
|
|
37
37
|
XsdCm* complex_types; /* name-carrying model roots */
|
|
38
38
|
XsdGroupDef* groups; /* top-level xs:group definitions */
|
|
39
|
+
XsdCm* default_open; /* xs:defaultOpenContent wildcard */
|
|
40
|
+
int default_oc_empty; /* appliesToEmpty="true" */
|
|
39
41
|
XsdAttrGroupDef* attr_groups;
|
|
40
42
|
XsdAttrDecl* top_attrs; /* top-level xs:attribute declarations */
|
|
41
43
|
XsdTypeAttrs* type_attrs;
|
|
42
44
|
XsdElementIcs* element_ics;
|
|
43
45
|
char* target_ns;
|
|
46
|
+
int version_11; /* xs:schema @version = "1.1" */
|
|
44
47
|
char* base_dir; /* schemaLocation resolution (file compile) */
|
|
45
48
|
int include_depth; /* include/import recursion guard */
|
|
46
49
|
void* validator; /* slice-4 parked error list */
|
|
@@ -80,6 +83,12 @@ static void xsd_register_complex(struct leptris_xsd_schema* s,
|
|
|
80
83
|
static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
81
84
|
LeptrisElement ct,
|
|
82
85
|
const char* name);
|
|
86
|
+
static XsdAssert* xsd_capture_assert(struct leptris_xsd_schema* s,
|
|
87
|
+
LeptrisElement e);
|
|
88
|
+
static XsdCm* xsd_capture_any(LeptrisElement any_child);
|
|
89
|
+
static void xsd_capture_alternatives(struct leptris_xsd_schema* s,
|
|
90
|
+
LeptrisElement decl_elem,
|
|
91
|
+
XsdElementDecl* d);
|
|
83
92
|
static XsdSimple* xsd_capture_simple(LeptrisElement st);
|
|
84
93
|
|
|
85
94
|
|
|
@@ -95,6 +104,15 @@ static XsdCm* xsd_cm_new(XsdCmKind kind) {
|
|
|
95
104
|
static void xsd_cm_free(XsdCm* cm) {
|
|
96
105
|
while (cm) {
|
|
97
106
|
XsdCm* next = cm->next;
|
|
107
|
+
XsdAssert* a = cm->asserts;
|
|
108
|
+
while (a) {
|
|
109
|
+
XsdAssert* an = a->next;
|
|
110
|
+
if (a->compiled) leptris_xquery_free(a->compiled);
|
|
111
|
+
free(a->test);
|
|
112
|
+
free(a);
|
|
113
|
+
a = an;
|
|
114
|
+
}
|
|
115
|
+
if (cm->oc_owned && cm->open_any) xsd_cm_free(cm->open_any);
|
|
98
116
|
xsd_cm_free(cm->first_child);
|
|
99
117
|
free(cm->name);
|
|
100
118
|
free(cm->type);
|
|
@@ -370,6 +388,9 @@ static XsdSimple* xsd_capture_simple(LeptrisElement st) {
|
|
|
370
388
|
simple->fraction_digits = val ? strtol(val, NULL, 10) : -1;
|
|
371
389
|
else if (strcmp(fl, "whiteSpace") == 0)
|
|
372
390
|
simple->whitespace = xsd_strdup(val);
|
|
391
|
+
else if (strcmp(fl, "assertion") == 0)
|
|
392
|
+
simple->assertion = xsd_strdup(
|
|
393
|
+
leptris_element_attribute(fe, "test"));
|
|
373
394
|
}
|
|
374
395
|
}
|
|
375
396
|
}
|
|
@@ -481,6 +502,7 @@ static int xsd_is_declaration(const char* local, const char* uri) {
|
|
|
481
502
|
static const char* names[] = {
|
|
482
503
|
"element", "attribute", "simpleType", "complexType",
|
|
483
504
|
"group", "attributeGroup", "notation", "include",
|
|
505
|
+
"defaultOpenContent",
|
|
484
506
|
"import", "redefine", NULL
|
|
485
507
|
};
|
|
486
508
|
for (int i = 0; names[i]; i++)
|
|
@@ -594,6 +616,10 @@ static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
|
|
|
594
616
|
}
|
|
595
617
|
s->target_ns = xsd_strdup(
|
|
596
618
|
leptris_element_attribute(root, "targetNamespace"));
|
|
619
|
+
{
|
|
620
|
+
const char* ver = leptris_element_attribute(root, "version");
|
|
621
|
+
s->version_11 = (ver && strcmp(ver, "1.1") == 0);
|
|
622
|
+
}
|
|
597
623
|
|
|
598
624
|
const char* local = NULL;
|
|
599
625
|
const char* prefix = NULL;
|
|
@@ -692,6 +718,7 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
|
|
|
692
718
|
if (d) {
|
|
693
719
|
d->name = xsd_strdup(nm);
|
|
694
720
|
d->type = xsd_strdup(ty);
|
|
721
|
+
xsd_capture_alternatives(s, (LeptrisElement)n, d);
|
|
695
722
|
d->fixed = xsd_strdup(
|
|
696
723
|
leptris_element_attribute((LeptrisElement)n,
|
|
697
724
|
"fixed"));
|
|
@@ -730,6 +757,29 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
|
|
|
730
757
|
leptris_element_attribute((LeptrisElement)n, "name");
|
|
731
758
|
if (nm)
|
|
732
759
|
xsd_capture_complex_model(s, (LeptrisElement)n, nm);
|
|
760
|
+
} else if (strcmp(local, "defaultOpenContent") == 0 && uri &&
|
|
761
|
+
!strcmp(uri, XSD_NS)) {
|
|
762
|
+
if (s->version_11) {
|
|
763
|
+
const char* ape = leptris_element_attribute(
|
|
764
|
+
(LeptrisElement)n, "appliesToEmpty");
|
|
765
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
766
|
+
leptris_element_as_node((LeptrisElement)n));
|
|
767
|
+
q && !s->default_open;
|
|
768
|
+
q = leptris_node_next_sibling(q)) {
|
|
769
|
+
if (leptris_node_get_type(q) !=
|
|
770
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
771
|
+
continue;
|
|
772
|
+
LeptrisElement qe = (LeptrisElement)q;
|
|
773
|
+
const char* ql = NULL;
|
|
774
|
+
leptris_element_expanded_name(qe, &ql, NULL, NULL);
|
|
775
|
+
if (ql && strcmp(ql, "any") == 0)
|
|
776
|
+
s->default_open = xsd_capture_any(qe);
|
|
777
|
+
}
|
|
778
|
+
if (s->default_open)
|
|
779
|
+
s->default_oc_empty =
|
|
780
|
+
(ape && strcmp(ape, "true") == 0);
|
|
781
|
+
}
|
|
782
|
+
continue;
|
|
733
783
|
} else if (strcmp(local, "attribute") == 0 && uri && !strcmp(uri, XSD_NS)) {
|
|
734
784
|
const char* nm =
|
|
735
785
|
leptris_element_attribute((LeptrisElement)n, "name");
|
|
@@ -803,6 +853,8 @@ static void xsd_free_simple_one(XsdSimple* t) {
|
|
|
803
853
|
free(t->max_inclusive);
|
|
804
854
|
free(t->max_exclusive);
|
|
805
855
|
free(t->whitespace);
|
|
856
|
+
if (t->assertion_q) leptris_xquery_free(t->assertion_q);
|
|
857
|
+
free(t->assertion);
|
|
806
858
|
free(t->item_type);
|
|
807
859
|
xsd_free_simple_one(t->item_def);
|
|
808
860
|
for (size_t i = 0; i < t->member_count; i++) free(t->members[i]);
|
|
@@ -854,6 +906,15 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
|
854
906
|
XsdElementDecl* d = s->elements;
|
|
855
907
|
while (d) {
|
|
856
908
|
XsdElementDecl* dn = d->next;
|
|
909
|
+
XsdAlternative* a = d->alternatives;
|
|
910
|
+
while (a) {
|
|
911
|
+
XsdAlternative* an = a->next;
|
|
912
|
+
if (a->compiled) leptris_xquery_free(a->compiled);
|
|
913
|
+
free(a->test);
|
|
914
|
+
free(a->type);
|
|
915
|
+
free(a);
|
|
916
|
+
a = an;
|
|
917
|
+
}
|
|
857
918
|
free(d->name);
|
|
858
919
|
free(d->type);
|
|
859
920
|
free(d->fixed);
|
|
@@ -894,6 +955,7 @@ LEPTRIS_API void leptris_xsd_free(LeptrisXsdSchema schema) {
|
|
|
894
955
|
free(g);
|
|
895
956
|
g = gn;
|
|
896
957
|
}
|
|
958
|
+
if (s->default_open) xsd_cm_free(s->default_open);
|
|
897
959
|
free(s->target_ns);
|
|
898
960
|
free(s->base_dir);
|
|
899
961
|
if (s->validator)
|
|
@@ -952,6 +1014,90 @@ static void xsd_register_complex(struct leptris_xsd_schema* s,
|
|
|
952
1014
|
}
|
|
953
1015
|
}
|
|
954
1016
|
|
|
1017
|
+
/* XSD 1.1: xs:alternative children of an element declaration. */
|
|
1018
|
+
static void xsd_capture_alternatives(struct leptris_xsd_schema* s,
|
|
1019
|
+
LeptrisElement decl_elem,
|
|
1020
|
+
XsdElementDecl* d) {
|
|
1021
|
+
if (!s->version_11) return;
|
|
1022
|
+
XsdAlternative* tail = NULL;
|
|
1023
|
+
for (LeptrisNodeRef n =
|
|
1024
|
+
leptris_node_first_child(leptris_element_as_node(decl_elem));
|
|
1025
|
+
n; n = leptris_node_next_sibling(n)) {
|
|
1026
|
+
if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1027
|
+
continue;
|
|
1028
|
+
LeptrisElement e = (LeptrisElement)n;
|
|
1029
|
+
const char* local = NULL;
|
|
1030
|
+
leptris_element_expanded_name(e, &local, NULL, NULL);
|
|
1031
|
+
if (!local || strcmp(local, "alternative") != 0) continue;
|
|
1032
|
+
const char* test = leptris_element_attribute(e, "test");
|
|
1033
|
+
const char* type = leptris_element_attribute(e, "type");
|
|
1034
|
+
if (!test || !type) continue;
|
|
1035
|
+
XsdAlternative* a = (XsdAlternative*)calloc(1, sizeof(*a));
|
|
1036
|
+
if (!a) continue;
|
|
1037
|
+
a->test = xsd_strdup(test);
|
|
1038
|
+
a->type = xsd_strdup(type);
|
|
1039
|
+
a->compiled = leptris_xquery_parse(test, strlen(test));
|
|
1040
|
+
if (tail)
|
|
1041
|
+
tail->next = a;
|
|
1042
|
+
else
|
|
1043
|
+
d->alternatives = a;
|
|
1044
|
+
tail = a;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
static XsdCm* xsd_capture_any(LeptrisElement any_child) {
|
|
1049
|
+
XsdCm* w = xsd_cm_new(XSD_CM_ANY);
|
|
1050
|
+
if (!w) return NULL;
|
|
1051
|
+
w->any_ns = xsd_strdup(
|
|
1052
|
+
leptris_element_attribute(any_child, "namespace"));
|
|
1053
|
+
const char* pc = leptris_element_attribute(any_child,
|
|
1054
|
+
"processContents");
|
|
1055
|
+
w->process_skip =
|
|
1056
|
+
(pc && (strcmp(pc, "skip") == 0 || strcmp(pc, "lax") == 0))
|
|
1057
|
+
? 1
|
|
1058
|
+
: 0;
|
|
1059
|
+
w->min = 0;
|
|
1060
|
+
w->max = -1;
|
|
1061
|
+
return w;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
static XsdAssert* xsd_capture_assert(struct leptris_xsd_schema* s,
|
|
1065
|
+
LeptrisElement e) {
|
|
1066
|
+
const char* test = leptris_element_attribute(e, "test");
|
|
1067
|
+
if (!test || !*test) return NULL;
|
|
1068
|
+
XsdAssert* a = (XsdAssert*)calloc(1, sizeof(*a));
|
|
1069
|
+
if (!a) return NULL;
|
|
1070
|
+
a->test = xsd_strdup(test);
|
|
1071
|
+
if (s->version_11) {
|
|
1072
|
+
a->compiled = leptris_xquery_parse(test, strlen(test));
|
|
1073
|
+
/* NULL = syntax error: evaluation reports the assertion
|
|
1074
|
+
* as failed (XSD 1.1: an error is a failure) */
|
|
1075
|
+
}
|
|
1076
|
+
return a;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* Append every xs:assert child under `container` to the type. */
|
|
1080
|
+
static void xsd_capture_assert_children(
|
|
1081
|
+
struct leptris_xsd_schema* s, LeptrisElement container,
|
|
1082
|
+
XsdCm* root) {
|
|
1083
|
+
XsdAssert* tail = root->asserts;
|
|
1084
|
+
while (tail && tail->next) tail = tail->next;
|
|
1085
|
+
for (LeptrisNodeRef n =
|
|
1086
|
+
leptris_node_first_child(leptris_element_as_node(container));
|
|
1087
|
+
n; n = leptris_node_next_sibling(n)) {
|
|
1088
|
+
if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1089
|
+
continue;
|
|
1090
|
+
LeptrisElement e = (LeptrisElement)n;
|
|
1091
|
+
const char* local = NULL;
|
|
1092
|
+
leptris_element_expanded_name(e, &local, NULL, NULL);
|
|
1093
|
+
if (!local || strcmp(local, "assert") != 0) continue;
|
|
1094
|
+
XsdAssert* a = xsd_capture_assert(s, e);
|
|
1095
|
+
if (!a) continue;
|
|
1096
|
+
if (!root->asserts) root->asserts = a;
|
|
1097
|
+
tail = a;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
955
1101
|
/* One complexType capture, shared by top-level declarations and
|
|
956
1102
|
* inline anonymous types: content model + derivation
|
|
957
1103
|
* (complexContent/simpleContent extension|restriction) + the
|
|
@@ -1026,6 +1172,9 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
|
1026
1172
|
root->first_child = xsd_cm_parse(s, dq, NULL);
|
|
1027
1173
|
attrs = xsd_capture_attr_rows(s, dq, 0);
|
|
1028
1174
|
}
|
|
1175
|
+
/* XSD 1.1: asserts nested under the derivation */
|
|
1176
|
+
if (s->version_11)
|
|
1177
|
+
xsd_capture_assert_children(s, dq, root);
|
|
1029
1178
|
}
|
|
1030
1179
|
} else if (strcmp(local, "simpleContent") == 0) {
|
|
1031
1180
|
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
@@ -1093,6 +1242,50 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
|
1093
1242
|
root->first_child = xsd_cm_parse(s, ct, NULL);
|
|
1094
1243
|
if (!attrs) attrs = xsd_capture_attr_rows(s, ct, 0);
|
|
1095
1244
|
}
|
|
1245
|
+
/* XSD 1.1: openContent on the type, else the schema default */
|
|
1246
|
+
if (s->version_11) {
|
|
1247
|
+
for (LeptrisNodeRef n =
|
|
1248
|
+
leptris_node_first_child(leptris_element_as_node(ct));
|
|
1249
|
+
n; n = leptris_node_next_sibling(n)) {
|
|
1250
|
+
if (leptris_node_get_type(n) != LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1251
|
+
continue;
|
|
1252
|
+
LeptrisElement e = (LeptrisElement)n;
|
|
1253
|
+
const char* ocl = NULL;
|
|
1254
|
+
leptris_element_expanded_name(e, &ocl, NULL, NULL);
|
|
1255
|
+
if (!ocl || strcmp(ocl, "openContent") != 0) continue;
|
|
1256
|
+
const char* mode = leptris_element_attribute(e, "mode");
|
|
1257
|
+
for (LeptrisNodeRef q = leptris_node_first_child(
|
|
1258
|
+
leptris_element_as_node(e));
|
|
1259
|
+
q && !root->open_any;
|
|
1260
|
+
q = leptris_node_next_sibling(q)) {
|
|
1261
|
+
if (leptris_node_get_type(q) !=
|
|
1262
|
+
LEPTRIS_NODE_TYPE_ELEMENT)
|
|
1263
|
+
continue;
|
|
1264
|
+
LeptrisElement qe = (LeptrisElement)q;
|
|
1265
|
+
const char* ql = NULL;
|
|
1266
|
+
leptris_element_expanded_name(qe, &ql, NULL, NULL);
|
|
1267
|
+
if (ql && strcmp(ql, "any") == 0) {
|
|
1268
|
+
root->open_any = xsd_capture_any(qe);
|
|
1269
|
+
if (root->open_any) root->oc_owned = 1;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
if (mode && strcmp(mode, "suffix") == 0)
|
|
1273
|
+
root->oc_mode = 1;
|
|
1274
|
+
else if (mode && strcmp(mode, "interleave") == 0)
|
|
1275
|
+
root->oc_mode = 2;
|
|
1276
|
+
else
|
|
1277
|
+
root->oc_mode = 0;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
if (!root->oc_mode && s->default_open && root->first_child)
|
|
1281
|
+
root->oc_mode = 2;
|
|
1282
|
+
if (!root->oc_mode && s->default_open && !root->first_child &&
|
|
1283
|
+
s->default_oc_empty)
|
|
1284
|
+
root->oc_mode = 2;
|
|
1285
|
+
if (root->oc_mode == 2 && !root->open_any && s->default_open)
|
|
1286
|
+
root->open_any = s->default_open;
|
|
1287
|
+
/* XSD 1.1: direct xs:assert children of the complexType */
|
|
1288
|
+
if (s->version_11) xsd_capture_assert_children(s, ct, root);
|
|
1096
1289
|
/* the NFA and model walkers consume ONE root particle —
|
|
1097
1290
|
* a multi-particle model (derivation splices) normalizes
|
|
1098
1291
|
* under a sequence */
|
|
@@ -1103,6 +1296,18 @@ static XsdCm* xsd_capture_complex_model(struct leptris_xsd_schema* s,
|
|
|
1103
1296
|
root->first_child = seq;
|
|
1104
1297
|
}
|
|
1105
1298
|
}
|
|
1299
|
+
/* open-content semantics ride the model root (the NFA builds
|
|
1300
|
+
* from ct->first_child, never the name wrapper) */
|
|
1301
|
+
if (root->first_child) {
|
|
1302
|
+
root->first_child->open_any = root->open_any;
|
|
1303
|
+
root->first_child->oc_mode = root->oc_mode;
|
|
1304
|
+
root->first_child->oc_owned = root->oc_owned;
|
|
1305
|
+
root->open_any = NULL;
|
|
1306
|
+
root->oc_owned = 0;
|
|
1307
|
+
} else if (root->open_any && root->oc_owned) {
|
|
1308
|
+
xsd_cm_free(root->open_any);
|
|
1309
|
+
root->open_any = NULL;
|
|
1310
|
+
}
|
|
1106
1311
|
xsd_register_complex(s, root, attrs, name);
|
|
1107
1312
|
return root;
|
|
1108
1313
|
}
|
|
@@ -1124,6 +1329,10 @@ int xsd_is_substitute(struct leptris_xsd_schema* s,
|
|
|
1124
1329
|
return 0;
|
|
1125
1330
|
}
|
|
1126
1331
|
|
|
1332
|
+
int xsd_schema_version_11(struct leptris_xsd_schema* s) {
|
|
1333
|
+
return s ? s->version_11 : 0;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1127
1336
|
XsdGroupDef* xsd_find_group(struct leptris_xsd_schema* s,
|
|
1128
1337
|
const char* name) {
|
|
1129
1338
|
if (!s || !name) return NULL;
|
|
@@ -56,20 +56,35 @@ static void cm_build_occurrence(CmNfa* n, XsdCm* node,
|
|
|
56
56
|
/* chain the group children: first reads `from`, last writes `to`.
|
|
57
57
|
* xs:all is evaluated in sequence order for now (its order-free
|
|
58
58
|
* semantics arrive with slice 4's all-semantics pass). */
|
|
59
|
+
/* XSD 1.1 open content: a wildcard self-loop at a junction lets
|
|
60
|
+
* any-namespace elements (per the wildcard's grammar) consume a
|
|
61
|
+
* child without advancing the model. */
|
|
62
|
+
static void oc_loop(CmNfa* n, XsdCm* node, int state) {
|
|
63
|
+
if (!node->open_any || !node->oc_mode) return;
|
|
64
|
+
nfa_trans(n, state, 0, node->open_any, state);
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
static void cm_build_children(CmNfa* n, XsdCm* node, int from, int to) {
|
|
60
68
|
XsdCm* c = node->first_child;
|
|
61
69
|
if (!c) {
|
|
62
70
|
nfa_trans(n, from, -1, NULL, to);
|
|
63
71
|
return;
|
|
64
72
|
}
|
|
73
|
+
int interleave =
|
|
74
|
+
(node->open_any && node->oc_mode == 2) ? 1 : 0;
|
|
65
75
|
int cursor = from;
|
|
76
|
+
if (interleave) oc_loop(n, node, cursor);
|
|
66
77
|
while (c->next) {
|
|
67
78
|
int mid = nfa_state(n);
|
|
68
79
|
cm_build_occurrence(n, c, cursor, mid);
|
|
69
80
|
cursor = mid;
|
|
81
|
+
if (interleave) oc_loop(n, node, cursor);
|
|
70
82
|
c = c->next;
|
|
71
83
|
}
|
|
72
84
|
cm_build_occurrence(n, c, cursor, to);
|
|
85
|
+
/* suffix (and interleave) wildcards may follow the sequence */
|
|
86
|
+
if (node->open_any && node->oc_mode)
|
|
87
|
+
oc_loop(n, node, to);
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
static void cm_build(CmNfa* n, XsdCm* node, int from, int to) {
|
|
@@ -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;
|
|
@@ -89,13 +91,14 @@ static void verrf(struct xsd_validator* v, const char* what,
|
|
|
89
91
|
static int text_valid(struct xsd_validator* v,
|
|
90
92
|
struct leptris_xsd_schema* s, const char* type,
|
|
91
93
|
const char* lexical, const char* what,
|
|
92
|
-
const char* name) {
|
|
94
|
+
const char* name, LeptrisElement elem) {
|
|
93
95
|
if (!type) return 1;
|
|
94
96
|
int r;
|
|
97
|
+
const XsdSimple* st = NULL;
|
|
95
98
|
if (strncmp(type, "xs:", 3) == 0)
|
|
96
99
|
r = xsd_builtin_valid(type, lexical);
|
|
97
100
|
else {
|
|
98
|
-
|
|
101
|
+
st = xsd_find_simple_pub(s, type);
|
|
99
102
|
if (!st) return 1; /* unresolved: accept */
|
|
100
103
|
r = xsd_simple_valid_chain(s, st, lexical);
|
|
101
104
|
}
|
|
@@ -103,6 +106,61 @@ static int text_valid(struct xsd_validator* v,
|
|
|
103
106
|
verrf(v, what, name, "lexical value does not match its type");
|
|
104
107
|
return 0;
|
|
105
108
|
}
|
|
109
|
+
/* XSD 1.1 xs:assertion facet (document validation only):
|
|
110
|
+
* $value binds the lexical — numeric lexicals bind bare,
|
|
111
|
+
* everything else as a string — and the context is the
|
|
112
|
+
* owning element. */
|
|
113
|
+
if (st && st->assertion && elem && v->doc) {
|
|
114
|
+
XsdSimple* mut = (XsdSimple*)st;
|
|
115
|
+
if (!mut->assertion_tried) {
|
|
116
|
+
mut->assertion_tried = 1;
|
|
117
|
+
if (xsd_schema_version_11(s)) {
|
|
118
|
+
/* eval_params binds DECLARED external variables —
|
|
119
|
+
* the test compiles under a $value declaration */
|
|
120
|
+
char wrapped[1024];
|
|
121
|
+
int w = snprintf(wrapped, sizeof(wrapped),
|
|
122
|
+
"declare variable $value external; %s",
|
|
123
|
+
mut->assertion);
|
|
124
|
+
if (w > 0 && (size_t)w < sizeof(wrapped))
|
|
125
|
+
mut->assertion_q =
|
|
126
|
+
leptris_xquery_parse(wrapped, (size_t)w);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (mut->assertion_q) {
|
|
130
|
+
char sel[256];
|
|
131
|
+
int numeric = 1;
|
|
132
|
+
for (const char* p = lexical; *p; p++)
|
|
133
|
+
if (!isdigit((unsigned char)*p) && *p != '.' &&
|
|
134
|
+
*p != '-' && *p != '+' && *p != 'e' && *p != 'E')
|
|
135
|
+
numeric = 0;
|
|
136
|
+
if (numeric && *lexical)
|
|
137
|
+
snprintf(sel, sizeof(sel), "%s", lexical);
|
|
138
|
+
else {
|
|
139
|
+
size_t w = 0;
|
|
140
|
+
sel[w++] = '\'';
|
|
141
|
+
for (const char* p = lexical; *p && w < sizeof(sel) - 3;
|
|
142
|
+
p++) {
|
|
143
|
+
if (*p == '\'') sel[w++] = '\'';
|
|
144
|
+
sel[w++] = *p;
|
|
145
|
+
}
|
|
146
|
+
sel[w++] = '\'';
|
|
147
|
+
sel[w] = 0;
|
|
148
|
+
}
|
|
149
|
+
const char* names[1] = {"value"};
|
|
150
|
+
const char* sels[1] = {sel};
|
|
151
|
+
LeptrisXPathResult r2 = leptris_xquery_eval_params(
|
|
152
|
+
mut->assertion_q, v->doc, elem, names, sels, 1);
|
|
153
|
+
int ebv = 0;
|
|
154
|
+
if (r2) {
|
|
155
|
+
ebv = leptris_xpath_result_boolean(r2);
|
|
156
|
+
leptris_xpath_result_free(r2);
|
|
157
|
+
}
|
|
158
|
+
if (!ebv) {
|
|
159
|
+
verrf(v, what, name, "assertion failed");
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
106
164
|
return 1;
|
|
107
165
|
}
|
|
108
166
|
|
|
@@ -231,7 +289,7 @@ static void validate_attributes(struct xsd_validator* v,
|
|
|
231
289
|
verrf(v, "attribute", a->name, "required but absent");
|
|
232
290
|
continue;
|
|
233
291
|
}
|
|
234
|
-
text_valid(v, s, a->type, val, "attribute", a->name);
|
|
292
|
+
text_valid(v, s, a->type, val, "attribute", a->name, elem);
|
|
235
293
|
if (a->fixed && strcmp(val, a->fixed) != 0)
|
|
236
294
|
verrf(v, "attribute", a->name,
|
|
237
295
|
"value does not match the fixed value");
|
|
@@ -248,14 +306,32 @@ static void validate_element(struct xsd_validator* v,
|
|
|
248
306
|
const XsdElementDecl* d = xsd_find_element(s, local);
|
|
249
307
|
if (!d) return; /* undeclared: lax at this depth (strict later) */
|
|
250
308
|
|
|
251
|
-
|
|
309
|
+
/* XSD 1.1: the first alternative whose test passes types the
|
|
310
|
+
* element for this instance (context = the element). */
|
|
311
|
+
const char* eff_type = d->type;
|
|
312
|
+
for (XsdAlternative* alt = d->alternatives; alt; alt = alt->next) {
|
|
313
|
+
int ebv = 0;
|
|
314
|
+
if (alt->compiled && v->doc) {
|
|
315
|
+
LeptrisXPathResult r =
|
|
316
|
+
leptris_xquery_eval(alt->compiled, v->doc, elem);
|
|
317
|
+
if (r) {
|
|
318
|
+
ebv = leptris_xpath_result_boolean(r);
|
|
319
|
+
leptris_xpath_result_free(r);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (ebv) {
|
|
323
|
+
eff_type = alt->type;
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (!eff_type) return; /* anyType */
|
|
252
328
|
if (d->fixed) {
|
|
253
329
|
const char* text = leptris_element_text(elem);
|
|
254
330
|
if (text && *text && strcmp(text, d->fixed) != 0)
|
|
255
331
|
verrf(v, "element", local,
|
|
256
332
|
"content does not match the fixed value");
|
|
257
333
|
}
|
|
258
|
-
validate_local(v, s, elem, local,
|
|
334
|
+
validate_local(v, s, elem, local, eff_type);
|
|
259
335
|
}
|
|
260
336
|
|
|
261
337
|
/* Validate one element against a type name that comes from a
|
|
@@ -270,11 +346,27 @@ static void validate_local(struct xsd_validator* v,
|
|
|
270
346
|
if (ct) {
|
|
271
347
|
validate_attributes(v, s, elem, xsd_find_type_attrs(s, type));
|
|
272
348
|
validate_children(v, s, elem, ct);
|
|
349
|
+
/* XSD 1.1: the type's xs:assert list — context is the
|
|
350
|
+
* element; evaluation errors are failures */
|
|
351
|
+
for (XsdAssert* a = ct->asserts; a; a = a->next) {
|
|
352
|
+
int ebv = 0;
|
|
353
|
+
if (a->compiled && v->doc) {
|
|
354
|
+
LeptrisXPathResult r =
|
|
355
|
+
leptris_xquery_eval(a->compiled, v->doc, elem);
|
|
356
|
+
if (r) {
|
|
357
|
+
ebv = leptris_xpath_result_boolean(r);
|
|
358
|
+
leptris_xpath_result_free(r);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!ebv)
|
|
362
|
+
verrf(v, "assertion", local, a->test ? a->test
|
|
363
|
+
: "(invalid)");
|
|
364
|
+
}
|
|
273
365
|
if (ct->text_type) {
|
|
274
366
|
const char* text = leptris_element_text(elem);
|
|
275
367
|
if (text && *text)
|
|
276
368
|
text_valid(v, s, ct->text_type, text, "element",
|
|
277
|
-
local);
|
|
369
|
+
local, elem);
|
|
278
370
|
}
|
|
279
371
|
return;
|
|
280
372
|
}
|
|
@@ -284,7 +376,7 @@ static void validate_local(struct xsd_validator* v,
|
|
|
284
376
|
xsd_find_simple_pub(s, type)) {
|
|
285
377
|
const char* text = leptris_element_text(elem);
|
|
286
378
|
if (text && *text)
|
|
287
|
-
text_valid(v, s, type, text, "element", local);
|
|
379
|
+
text_valid(v, s, type, text, "element", local, elem);
|
|
288
380
|
}
|
|
289
381
|
}
|
|
290
382
|
|
|
@@ -509,6 +601,7 @@ void xsd_validator_free(struct xsd_validator* v) {
|
|
|
509
601
|
|
|
510
602
|
int xsd_validator_run(struct xsd_validator* v, LeptrisDocument doc) {
|
|
511
603
|
if (!v || !doc) return -1;
|
|
604
|
+
v->doc = doc; /* XSD 1.1: assertion evaluation context */
|
|
512
605
|
LeptrisElement root = leptris_document_root(doc);
|
|
513
606
|
if (!root) return -1;
|
|
514
607
|
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;
|
|
@@ -1119,3 +1119,280 @@ TEST(XsdCompileFile, MissingFileIsNullWithStatus) {
|
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
1121
|
} // namespace
|
|
1122
|
+
|
|
1123
|
+
// ---- tier 2 (#1075): xs:assert --------------------------------------
|
|
1124
|
+
namespace {
|
|
1125
|
+
|
|
1126
|
+
const char* k_assert_schema =
|
|
1127
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1128
|
+
" version=\"1.1\">"
|
|
1129
|
+
"<xs:complexType name=\"boxT\">"
|
|
1130
|
+
"<xs:sequence>"
|
|
1131
|
+
"<xs:element name=\"item\" type=\"xs:token\" minOccurs=\"0\""
|
|
1132
|
+
" maxOccurs=\"unbounded\"/>"
|
|
1133
|
+
"</xs:sequence>"
|
|
1134
|
+
"<xs:attribute name=\"qty\" type=\"xs:integer\"/>"
|
|
1135
|
+
"<xs:assert test=\"count(item) <= 2\"/>"
|
|
1136
|
+
"</xs:complexType>"
|
|
1137
|
+
"<xs:element name=\"box\" type=\"boxT\"/>"
|
|
1138
|
+
"</xs:schema>";
|
|
1139
|
+
|
|
1140
|
+
TEST(XsdAssert11, ComplexTypeAssertionEnforces) {
|
|
1141
|
+
EXPECT_EQ(validate_doc(k_assert_schema,
|
|
1142
|
+
"<box qty=\"1\"><item>a</item>"
|
|
1143
|
+
"</box>"), 1);
|
|
1144
|
+
EXPECT_EQ(validate_doc(k_assert_schema,
|
|
1145
|
+
"<box qty=\"1\"><item>a</item><item>b</item>"
|
|
1146
|
+
"</box>"), 1);
|
|
1147
|
+
/* the assertion fails at three items */
|
|
1148
|
+
EXPECT_EQ(validate_doc(k_assert_schema,
|
|
1149
|
+
"<box qty=\"1\"><item>a</item><item>b</item>"
|
|
1150
|
+
"<item>c</item></box>"), 0);
|
|
1151
|
+
/* attributes ride the assertion context too */
|
|
1152
|
+
EXPECT_EQ(validate_doc(k_assert_schema,
|
|
1153
|
+
"<box qty=\"9\"><item>a</item>"
|
|
1154
|
+
"<item>b</item><item>c</item></box>"), 0);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
const char* k_assert_attr_schema =
|
|
1158
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1159
|
+
" version=\"1.1\">"
|
|
1160
|
+
"<xs:complexType name=\"pairT\">"
|
|
1161
|
+
"<xs:attribute name=\"lo\" type=\"xs:integer\"/>"
|
|
1162
|
+
"<xs:attribute name=\"hi\" type=\"xs:integer\"/>"
|
|
1163
|
+
"<xs:assert test=\"number(@lo) <= number(@hi)\"/>"
|
|
1164
|
+
"</xs:complexType>"
|
|
1165
|
+
"<xs:element name=\"p\" type=\"pairT\"/>"
|
|
1166
|
+
"</xs:schema>";
|
|
1167
|
+
|
|
1168
|
+
TEST(XsdAssert11, AttributeComparisonAssertion) {
|
|
1169
|
+
EXPECT_EQ(validate_doc(k_assert_attr_schema,
|
|
1170
|
+
"<p lo=\"1\" hi=\"3\"/>"), 1);
|
|
1171
|
+
EXPECT_EQ(validate_doc(k_assert_attr_schema,
|
|
1172
|
+
"<p lo=\"4\" hi=\"3\"/>"), 0);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/* assertions nested under complexContent/extension also bind */
|
|
1176
|
+
TEST(XsdAssert11, ExtensionAssertionEnforces) {
|
|
1177
|
+
const char* x =
|
|
1178
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1179
|
+
" version=\"1.1\">"
|
|
1180
|
+
"<xs:complexType name=\"baseT\">"
|
|
1181
|
+
"<xs:sequence><xs:element name=\"a\" type=\"xs:token\"/>"
|
|
1182
|
+
"</xs:sequence>"
|
|
1183
|
+
"</xs:complexType>"
|
|
1184
|
+
"<xs:complexType name=\"extT\">"
|
|
1185
|
+
"<xs:complexContent>"
|
|
1186
|
+
"<xs:extension base=\"baseT\">"
|
|
1187
|
+
"<xs:sequence><xs:element name=\"b\" type=\"xs:token\"/>"
|
|
1188
|
+
"</xs:sequence>"
|
|
1189
|
+
"<xs:assert test=\"a = b\"/>"
|
|
1190
|
+
"</xs:extension>"
|
|
1191
|
+
"</xs:complexContent>"
|
|
1192
|
+
"</xs:complexType>"
|
|
1193
|
+
"<xs:element name=\"e\" type=\"extT\"/>"
|
|
1194
|
+
"</xs:schema>";
|
|
1195
|
+
EXPECT_EQ(validate_doc(x, "<e><a>t</a><b>t</b></e>"), 1);
|
|
1196
|
+
EXPECT_EQ(validate_doc(x, "<e><a>t</a><b>u</b></e>"), 0);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/* 1.0-labelled schemas ignore the construct (XSD 1.0 validators
|
|
1200
|
+
* see unknown elements) — no assertion enforcement */
|
|
1201
|
+
TEST(XsdAssert11, Version10IgnoresAssertions) {
|
|
1202
|
+
const char* x =
|
|
1203
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1204
|
+
" version=\"1.0\">"
|
|
1205
|
+
"<xs:complexType name=\"boxT\">"
|
|
1206
|
+
"<xs:sequence>"
|
|
1207
|
+
"<xs:element name=\"item\" type=\"xs:token\" minOccurs=\"0\""
|
|
1208
|
+
" maxOccurs=\"unbounded\"/>"
|
|
1209
|
+
"</xs:sequence>"
|
|
1210
|
+
"<xs:assert test=\"count(item) <= 1\"/>"
|
|
1211
|
+
"</xs:complexType>"
|
|
1212
|
+
"<xs:element name=\"box\" type=\"boxT\"/>"
|
|
1213
|
+
"</xs:schema>";
|
|
1214
|
+
EXPECT_EQ(validate_doc(x,
|
|
1215
|
+
"<box><item>a</item><item>b</item></box>"), 1);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
} // namespace
|
|
1219
|
+
|
|
1220
|
+
// ---- tier 2 (#1075): xs:assertion on simpleTypes -------------------
|
|
1221
|
+
namespace {
|
|
1222
|
+
|
|
1223
|
+
const char* k_sa_schema =
|
|
1224
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1225
|
+
" version=\"1.1\">"
|
|
1226
|
+
"<xs:simpleType name=\"small\">"
|
|
1227
|
+
"<xs:restriction base=\"xs:integer\">"
|
|
1228
|
+
"<xs:assertion test=\"$value < 10\"/>"
|
|
1229
|
+
"</xs:restriction>"
|
|
1230
|
+
"</xs:simpleType>"
|
|
1231
|
+
"<xs:simpleType name=\"word\">"
|
|
1232
|
+
"<xs:restriction base=\"xs:string\">"
|
|
1233
|
+
"<xs:assertion test=\"string-length($value) <= 3\"/>"
|
|
1234
|
+
"</xs:restriction>"
|
|
1235
|
+
"</xs:simpleType>"
|
|
1236
|
+
"<xs:element name=\"n\" type=\"small\"/>"
|
|
1237
|
+
"<xs:element name=\"w\" type=\"word\"/>"
|
|
1238
|
+
"</xs:schema>";
|
|
1239
|
+
|
|
1240
|
+
TEST(XsdAssertion11, SimpleTypeValueAssertions) {
|
|
1241
|
+
EXPECT_EQ(validate_doc(k_sa_schema, "<n>5</n>"), 1);
|
|
1242
|
+
EXPECT_EQ(validate_doc(k_sa_schema, "<n>50</n>"), 0);
|
|
1243
|
+
EXPECT_EQ(validate_doc(k_sa_schema, "<w>abc</w>"), 1);
|
|
1244
|
+
EXPECT_EQ(validate_doc(k_sa_schema, "<w>abcd</w>"), 0);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
} // namespace
|
|
1248
|
+
|
|
1249
|
+
// ---- tier 2 (#1075): open content ----------------------------------
|
|
1250
|
+
namespace {
|
|
1251
|
+
|
|
1252
|
+
const char* k_oc_interleave =
|
|
1253
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1254
|
+
" version=\"1.1\">"
|
|
1255
|
+
"<xs:complexType name=\"tT\">"
|
|
1256
|
+
"<xs:sequence>"
|
|
1257
|
+
"<xs:element name=\"a\" type=\"xs:token\"/>"
|
|
1258
|
+
"<xs:element name=\"b\" type=\"xs:token\"/>"
|
|
1259
|
+
"</xs:sequence>"
|
|
1260
|
+
"<xs:openContent mode=\"interleave\">"
|
|
1261
|
+
"<xs:any namespace=\"##any\" processContents=\"lax\"/>"
|
|
1262
|
+
"</xs:openContent>"
|
|
1263
|
+
"</xs:complexType>"
|
|
1264
|
+
"<xs:element name=\"e\" type=\"tT\"/>"
|
|
1265
|
+
"</xs:schema>";
|
|
1266
|
+
|
|
1267
|
+
TEST(XsdOpenContent11, InterleavedWildcardsBindAnywhere) {
|
|
1268
|
+
/* the plain sequence */
|
|
1269
|
+
EXPECT_EQ(validate_doc(k_oc_interleave,
|
|
1270
|
+
"<e><a>1</a><b>2</b></e>"), 1);
|
|
1271
|
+
/* foreign element before, between, after */
|
|
1272
|
+
EXPECT_EQ(validate_doc(k_oc_interleave,
|
|
1273
|
+
"<e><q/><a>1</a><b>2</b></e>"), 1);
|
|
1274
|
+
EXPECT_EQ(validate_doc(k_oc_interleave,
|
|
1275
|
+
"<e><a>1</a><q/><b>2</b></e>"), 1);
|
|
1276
|
+
EXPECT_EQ(validate_doc(k_oc_interleave,
|
|
1277
|
+
"<e><a>1</a><b>2</b><q/></e>"), 1);
|
|
1278
|
+
/* the sequence itself still enforces order */
|
|
1279
|
+
EXPECT_EQ(validate_doc(k_oc_interleave,
|
|
1280
|
+
"<e><b>2</b><a>1</a></e>"), 0);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
const char* k_oc_suffix =
|
|
1284
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1285
|
+
" version=\"1.1\">"
|
|
1286
|
+
"<xs:complexType name=\"tT\">"
|
|
1287
|
+
"<xs:sequence>"
|
|
1288
|
+
"<xs:element name=\"a\" type=\"xs:token\"/>"
|
|
1289
|
+
"</xs:sequence>"
|
|
1290
|
+
"<xs:openContent mode=\"suffix\">"
|
|
1291
|
+
"<xs:any namespace=\"##any\" processContents=\"lax\"/>"
|
|
1292
|
+
"</xs:openContent>"
|
|
1293
|
+
"</xs:complexType>"
|
|
1294
|
+
"<xs:element name=\"e\" type=\"tT\"/>"
|
|
1295
|
+
"</xs:schema>";
|
|
1296
|
+
|
|
1297
|
+
TEST(XsdOpenContent11, SuffixWildcardsBindOnlyAtTheEnd) {
|
|
1298
|
+
EXPECT_EQ(validate_doc(k_oc_suffix, "<e><a>1</a><q/></e>"), 1);
|
|
1299
|
+
EXPECT_EQ(validate_doc(k_oc_suffix, "<e><a>1</a><q/><r/></e>"), 1);
|
|
1300
|
+
EXPECT_EQ(validate_doc(k_oc_suffix, "<e><q/><a>1</a></e>"), 0);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
const char* k_oc_default =
|
|
1304
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1305
|
+
" version=\"1.1\">"
|
|
1306
|
+
"<xs:defaultOpenContent mode=\"interleave\">"
|
|
1307
|
+
"<xs:any namespace=\"##any\" processContents=\"lax\"/>"
|
|
1308
|
+
"</xs:defaultOpenContent>"
|
|
1309
|
+
"<xs:complexType name=\"tT\">"
|
|
1310
|
+
"<xs:sequence>"
|
|
1311
|
+
"<xs:element name=\"a\" type=\"xs:token\"/>"
|
|
1312
|
+
"</xs:sequence>"
|
|
1313
|
+
"</xs:complexType>"
|
|
1314
|
+
"<xs:element name=\"e\" type=\"tT\"/>"
|
|
1315
|
+
"</xs:schema>";
|
|
1316
|
+
|
|
1317
|
+
TEST(XsdOpenContent11, DefaultOpenContentApplies) {
|
|
1318
|
+
EXPECT_EQ(validate_doc(k_oc_default, "<e><a>1</a></e>"), 1);
|
|
1319
|
+
EXPECT_EQ(validate_doc(k_oc_default, "<e><a>1</a><q/></e>"), 1);
|
|
1320
|
+
EXPECT_EQ(validate_doc(k_oc_default, "<e><q/><a>1</a></e>"), 1);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
} // namespace
|
|
1324
|
+
|
|
1325
|
+
// ---- tier 2 (#1075): conditional type assignment --------------
|
|
1326
|
+
namespace {
|
|
1327
|
+
|
|
1328
|
+
const char* k_alt_schema =
|
|
1329
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
|
|
1330
|
+
" version=\"1.1\">"
|
|
1331
|
+
"<xs:complexType name=\"circleT\">"
|
|
1332
|
+
"<xs:sequence><xs:element name=\"r\" type=\"xs:integer\"/>"
|
|
1333
|
+
"</xs:sequence>"
|
|
1334
|
+
"</xs:complexType>"
|
|
1335
|
+
"<xs:complexType name=\"squareT\">"
|
|
1336
|
+
"<xs:sequence><xs:element name=\"s\" type=\"xs:string\"/>"
|
|
1337
|
+
"</xs:sequence>"
|
|
1338
|
+
"</xs:complexType>"
|
|
1339
|
+
"<xs:complexType name=\"fallbackT\">"
|
|
1340
|
+
"<xs:sequence><xs:element name=\"u\" type=\"xs:token\"/>"
|
|
1341
|
+
"</xs:sequence>"
|
|
1342
|
+
"</xs:complexType>"
|
|
1343
|
+
"<xs:element name=\"shape\" type=\"fallbackT\">"
|
|
1344
|
+
"<xs:alternative test=\"@kind = 'circle'\" type=\"circleT\"/>"
|
|
1345
|
+
"<xs:alternative test=\"@kind = 'square'\" type=\"squareT\"/>"
|
|
1346
|
+
"</xs:element>"
|
|
1347
|
+
"</xs:schema>";
|
|
1348
|
+
|
|
1349
|
+
TEST(XsdAlternative11, FirstMatchingAlternativeTypes) {
|
|
1350
|
+
/* circle alternative */
|
|
1351
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1352
|
+
"<shape kind=\"circle\"><r>2</r></shape>"), 1);
|
|
1353
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1354
|
+
"<shape kind=\"circle\"><r>x</r></shape>"), 0);
|
|
1355
|
+
/* square alternative */
|
|
1356
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1357
|
+
"<shape kind=\"square\"><s>hi</s></shape>"), 1);
|
|
1358
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1359
|
+
"<shape kind=\"square\"><r>2</r></shape>"), 0);
|
|
1360
|
+
/* no alternative matches: the declared fallback type applies */
|
|
1361
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1362
|
+
"<shape kind=\"blob\"><u>t</u></shape>"), 1);
|
|
1363
|
+
EXPECT_EQ(validate_doc(k_alt_schema,
|
|
1364
|
+
"<shape kind=\"blob\"><r>2</r></shape>"), 0);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
} // namespace
|
|
1368
|
+
|
|
1369
|
+
/* #1615 regression pin: a union combining memberTypes with inline
|
|
1370
|
+
* anonymous members consults BOTH member sets (the issue reported
|
|
1371
|
+
* over-acceptance through a stale binding binary; the engine was
|
|
1372
|
+
* verified correct on main, the tag, and every published gem —
|
|
1373
|
+
* this pins the behavior in CI, binary-independent). */
|
|
1374
|
+
TEST(XsdDatatypes, UnionMixesNamedAndInlineMembers) {
|
|
1375
|
+
const char* x =
|
|
1376
|
+
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
|
|
1377
|
+
"<xs:simpleType name=\"intOrAuto\">"
|
|
1378
|
+
"<xs:union memberTypes=\"xs:integer\">"
|
|
1379
|
+
"<xs:simpleType>"
|
|
1380
|
+
"<xs:restriction base=\"xs:token\">"
|
|
1381
|
+
"<xs:enumeration value=\"auto\"/>"
|
|
1382
|
+
"</xs:restriction>"
|
|
1383
|
+
"</xs:simpleType>"
|
|
1384
|
+
"</xs:union>"
|
|
1385
|
+
"</xs:simpleType>"
|
|
1386
|
+
"<xs:element name=\"v\" type=\"intOrAuto\"/>"
|
|
1387
|
+
"</xs:schema>";
|
|
1388
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
1389
|
+
LeptrisXsdSchema s = leptris_xsd_compile(x, strlen(x), &st);
|
|
1390
|
+
ASSERT_NE(s, (LeptrisXsdSchema)0);
|
|
1391
|
+
EXPECT_EQ(leptris_xsd_simple_valid(s, "intOrAuto", "42"), 1);
|
|
1392
|
+
EXPECT_EQ(leptris_xsd_simple_valid(s, "intOrAuto", "auto"), 1);
|
|
1393
|
+
EXPECT_EQ(leptris_xsd_simple_valid(s, "intOrAuto", "zz"), 0);
|
|
1394
|
+
leptris_xsd_free(s);
|
|
1395
|
+
EXPECT_EQ(validate_doc(x, "<v>zz</v>"), 0);
|
|
1396
|
+
EXPECT_EQ(validate_doc(x, "<v>42</v>"), 1);
|
|
1397
|
+
EXPECT_EQ(validate_doc(x, "<v>auto</v>"), 1);
|
|
1398
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
|
3
3
|
"name": "leptris",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.333",
|
|
5
5
|
"description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
|
|
6
6
|
"homepage": "https://github.com/leptris/leptris",
|
|
7
7
|
"license": "MIT",
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.333.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|