Skip to content

Commit f9b3e86

Browse files
committed
$dynamicAnchor creates fragment, no base URI stuff
Instead of using a boolean (which never really fit with how the similarly named "$anchor" worked, and meant only one dynamic resolution was possible at a time) and messing with base URIs and re-resolving URI-references (a topic that creates plenty of confusion even on its own), use a fragment name the same as "$anchor" and make "$dynamicRef" work by just looking for the outermost resource with a matching "$dynamicAnchor" fragment name. This stil requires that the initial "$dynamicRef" target URI be a valid URI, with a fragment created by "$dynamicAnchor", in order to produce the dynamic behavior. This ensures that it is always clear which schemas are dynamic extension points and which are not.
1 parent 1c9d8d2 commit f9b3e86

File tree

1 file changed

+76
-103
lines changed

1 file changed

+76
-103
lines changed

jsonschema-core.xml

Lines changed: 76 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -623,11 +623,9 @@
623623
Keywords MAY be defined with a partial value, such as a URI-reference,
624624
which must be resolved against another value, such as another
625625
URI-reference or a full URI, which is found through the lexical
626-
structure of the JSON document. The "$id" core keyword and
627-
the "base" JSON Hyper-Schema keyword are examples of this sort
628-
of behavior. Additionally, "$ref" and "$dyanmicRef" from
629-
this specification resolve their values in this way, although
630-
they do not change how further values are resolved.
626+
structure of the JSON document. The "$id", "$ref", and
627+
"$dyanmicRef" core keywords, and the "base" JSON Hyper-Schema
628+
keyword, are examples of this sort of behavior.
631629
</t>
632630
<t>
633631
Note that some keywords, such as "$schema", apply to the lexical
@@ -724,7 +722,8 @@
724722
While custom identifier keywords are possible, vocabulary designers should
725723
take care not to disrupt the functioning of core keywords. For example,
726724
the "$dyanmicAnchor" keyword in this specification limits its URI resolution
727-
effects to the matching "$dyanmicRef" keyword, leaving "$ref" undisturbed.
725+
effects to the matching "$dyanmicRef" keyword, leaving the behavior
726+
of "$ref" undisturbed.
728727
</t>
729728
</section>
730729
<section title="Applicators" anchor="applicators">
@@ -775,7 +774,7 @@
775774
For some by-reference applicators, such as
776775
<xref target="ref">"$ref"</xref>, the referenced schema can be determined
777776
by static analysis of the schema document's lexical scope. Others,
778-
such as "$dyanmicRef" and "$dyanmicAnchor", may make use of dynamic
777+
such as "$dyanmicRef" (with "$dyanmicAnchor"), may make use of dynamic
779778
scoping, and therefore only be resolvable in the process of evaluating
780779
the schema with an instance.
781780
</t>
@@ -1377,8 +1376,7 @@
13771376
</t>
13781377
</section>
13791378
</section>
1380-
<section title='Defining location-independent identifiers with "$anchor"'
1381-
anchor="anchor">
1379+
<section title="Defining location-independent identifiers" anchor="anchor">
13821380
<t>
13831381
Using JSON Pointer fragments requires knowledge of the structure of the schema.
13841382
When writing schema documents with the intention to provide re-usable
@@ -1387,8 +1385,32 @@
13871385
without requiring JSON Pointer references to be updated.
13881386
</t>
13891387
<t>
1390-
The "$anchor" keyword is used to specify such a fragment. It is an
1391-
identifier keyword that can only be used to create plain name fragments.
1388+
The "$anchor" and "$dynamicAnchor" keywords are used to specify such
1389+
a fragments. They are identifier keywords that can only be used to create
1390+
plain name fragments, rather than absolute URIs as seen with "$id".
1391+
The behavior of the created fragment is identical for both keywords.
1392+
</t>
1393+
<t>
1394+
The base URI to which the resulting fragment is appended is the canonical
1395+
URI of the schema resource containing the "$anchor" or "$dynamicAnchor"
1396+
in question. As discussed in the previous section, this is either the
1397+
nearest "$id" in the same or parent schema object, or the base URI
1398+
for the document as determined according to RFC 3986.
1399+
</t>
1400+
<t>
1401+
Separately from the usual usage of URIs, "$dynamicAnchor"
1402+
indicates that the fragment is an extension point when used with
1403+
the "$dynamicRef" keyword. This low-level, advanced feature
1404+
makes it easier to extend recursive schemas such as the meta-schemas,
1405+
without imposing any particular semantics on that extension.
1406+
See the section on <xref target="dynamic-ref">"$dynamicRef"</xref>
1407+
for details.
1408+
</t>
1409+
<t>
1410+
In most cases, the normal fragment behavior both sufficies and
1411+
is more intuitive. Therefore it is RECOMMENDED that "$anchor"
1412+
be used to create plain name fragments unless there is a clear
1413+
need for "$dynamicAnchor".
13921414
</t>
13931415
<t>
13941416
If present, the value of this keyword MUST be a string and MUST start with
@@ -1403,12 +1425,9 @@
14031425
</cref>
14041426
</t>
14051427
<t>
1406-
The base URI to which the resulting fragment is appended is determined
1407-
by the "$id" keyword as explained in the previous section.
1408-
Two "$anchor" keywords in the same schema document MAY have the same
1409-
value if they apply to different base URIs, as the resulting full URIs
1410-
will be distinct. However, the effect of two "$anchor" keywords with the
1411-
same value and the same base URI is undefined. Implementations MAY
1428+
The effect of specifying the same fragment name multiple times within
1429+
the same resource, using any combination of "$anchor" and/or
1430+
"$dynamicAnchor", is undefined. Implementations MAY
14121431
raise an error if such usage is detected.
14131432
</t>
14141433
</section>
@@ -1417,9 +1436,7 @@
14171436
<t>
14181437
Several keywords can be used to reference a schema which is to be applied to the
14191438
current instance location. "$ref" and "$dyanmicRef" are applicator
1420-
keywords, applying the referenced schema to the instance. "$dyanmicAnchor"
1421-
is an identifier keyword that controls how the base URI for resolving
1422-
the URI-reference value of "$dyanmicRef is determined.
1439+
keywords, applying the referenced schema to the instance.
14231440
</t>
14241441
<t>
14251442
As the values of "$ref" and "$dynamicRef" are URI References, this allows
@@ -1447,103 +1464,59 @@
14471464
<t>
14481465
The value of the "$ref" property MUST be a string which is a URI-Reference.
14491466
Resolved against the current URI base, it produces the URI of the schema
1450-
to apply.
1467+
to apply. This resolution is safe to perform on schema load, as the
1468+
process of evaluating an instance cannot change how the reference resolves.
14511469
</t>
14521470
</section>
14531471

1454-
<section title='Dynamic References with "$dynamicRef" and "$dynamicAnchor"'
1455-
anchor="dynamic-ref">
1472+
<section title='Dynamic References with "$dynamicRef"' anchor="dynamic-ref">
1473+
<t>
1474+
The "$dynamicRef" keyword is an applicator that allows for deferring the
1475+
full resolution until runtime, at which point it is resolved each time it is
1476+
encountered while evaluating an instance.
1477+
</t>
1478+
<t>
1479+
Together with "$dynamicAnchor", "$dynamicRef" implements a cooperative
1480+
extension mechanism that is primarily useful with recursive schemas
1481+
(schemas that reference themselves). Both the extension point and the
1482+
runtime-determined extension target are defined with "$dynamicAnchor",
1483+
and only exhibit runtime dynamic behavior when referenced with
1484+
"$dynamicRef".
1485+
</t>
14561486
<t>
1457-
The "$dyanmicRef" and "$dyanmicAnchor" keywords are used to construct
1458-
extensible recursive schemas. A recursive schema is one that has
1459-
a reference to its own root, identified by the empty fragment
1460-
URI reference ("#").
1487+
The value of the "$dynamicRef" property MUST be a string which is
1488+
a URI-Reference. Resolved against the current URI base, it produces
1489+
the URI used as the starting point for runtime resolution. This initial
1490+
resolution is safe to perform on schema load.
14611491
</t>
14621492
<t>
1463-
Simply stated, a "$dynamicRef" behaves identically to "$ref", except
1464-
when its target schema contains "$dynamicAnchor" with a value of true.
1465-
In that case, the dynamic scope is examined to determine a new base URI,
1466-
and the URI-reference in "$dynamicRef" is re-evaluated against that
1467-
base URI. Unlike base URI changes with "$id", changes with
1468-
"$dynamicAnchor" are calculated each time a "$dynamicRef" is
1469-
resolved, and do not impact any other keywords.
1493+
If the initially resolved starting point URI includes a fragment that
1494+
was created by the "$dynamicAnchor" keyword, the initial URI MUST be
1495+
replaced by the URI (including the fragment) for the outermost schema
1496+
resource in the <xref target="scopes">dynamic scope</xref> that defines
1497+
an identically named fragment with "$dynamicAnchor".
1498+
<cref>
1499+
Requiring both the initial and final URI fragment to be defined
1500+
by "$dynamicAnchor" ensures that the more common "$anchor"
1501+
never unexpectedly changes the dynamic resolution process
1502+
due to a naming conflict across resources. Users of
1503+
"$dynamicAnchor" are expected to be aware of the possibility
1504+
of such name collisions, while users of "$anchor" are not.
1505+
</cref>
14701506
</t>
14711507
<t>
1472-
For an example using these keyword, see appendix
1508+
Otherwise, its behavior is identical to "$ref", and no runtime
1509+
resolution is needed.
1510+
</t>
1511+
<t>
1512+
For a full example using theses keyword, see appendix
14731513
<xref target="recursive-example" format="counter" />.
14741514
<cref>
1475-
The difference between the hyper-schema meta-schema in previous
1515+
The difference between the hyper-schema meta-schema in pre-2019
14761516
drafts and an this draft dramatically demonstrates the utility
14771517
of these keywords.
14781518
</cref>
14791519
</t>
1480-
<section title='Dynamically recursive references with "$dyanmicRef"'>
1481-
<t>
1482-
The value of the "$dynamicRef" property MUST be a string which is
1483-
a URI-reference. It is a by-reference applicator that uses
1484-
a dynamically calculated base URI to resolve its value.
1485-
</t>
1486-
<t>
1487-
The behavior of this keyword is defined only for the value "#".
1488-
Implementations MAY choose to consider other values to be errors.
1489-
<cref>
1490-
This restriction may be relaxed in the future, but to date only
1491-
the value "#" has a clear use case.
1492-
</cref>
1493-
</t>
1494-
<t>
1495-
The value of "$dynamicRef" is initially resolved against the
1496-
current base URI, in the same manner as for "$ref".
1497-
</t>
1498-
<t>
1499-
The schema identified by the resulting URI is examined for the
1500-
presence of "$dynamicAnchor", and a new base URI is calculated
1501-
as described for that keyword in the following section.
1502-
</t>
1503-
<t>
1504-
Finally, the value of "$dynamicRef" is resolved against the
1505-
new base URI determined according to "$dynamicAnchor" producing
1506-
the final resolved reference URI.
1507-
</t>
1508-
<t>
1509-
Note that in the absence of "$dynamicAnchor" (and in some cases
1510-
when it is present), "$dynamicRef"'s behavior is identical to
1511-
that of "$ref".
1512-
</t>
1513-
<t>
1514-
As with "$ref", the results of this keyword are the results of the
1515-
referenced schema.
1516-
</t>
1517-
</section>
1518-
<section title='Enabling Recursion with "$dynamicAnchor"'>
1519-
<t>
1520-
The value of the "$dynamicAnchor" property MUST be a boolean.
1521-
</t>
1522-
<t>
1523-
"$dynamicAnchor" is used to dynamically identify a base URI
1524-
at runtime for "$dynamicRef" by marking where such a calculation
1525-
can start, and where it stops. This keyword MUST NOT affect the
1526-
base URI of other keywords, unless they are explicitly defined
1527-
to rely on it.
1528-
</t>
1529-
<t>
1530-
If set to true, then when the containing schema object is used
1531-
as a target of "$dynamicRef", a new base URI is determined
1532-
by examining the <xref target="scopes">dynamic scope</xref> for
1533-
the outermost schema that also contains "$dynamicAnchor"
1534-
with a value of true. The base URI of that schema is then used
1535-
as the dynamic base URI.
1536-
</t>
1537-
<t>
1538-
If no such schema exists, then the base URI is unchanged.
1539-
</t>
1540-
<t>
1541-
If this keyword is set to false, the base URI is unchanged.
1542-
</t>
1543-
<t>
1544-
Omitting this keyword has the same behavior as a value of false.
1545-
</t>
1546-
</section>
15471520
</section>
15481521

15491522
</section>

0 commit comments

Comments
 (0)