Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecation of classSpec/@generate and classRef/@expand with alternative solutions. #2549

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

raffazizzi
Copy link
Contributor

@raffazizzi raffazizzi commented Apr 13, 2024

This PR is work in progress to address issue #2369

  • Deprecate @generate on <classSpec> and implement a 6-month deprecation period.
  • Replace @expand on <classRef> in the 4 instances where it is mentioned in the Guidelines with <elementRef>s
  • Deprecate @expand on <classRef> for 6 months, and make <classRef> a child of <alternate> instead (and potentially <interleave> once added. See Add interleave element (and deprecate sequence/@preserveOrder)  #2538.
  • Adjust guidelines accordingly.

@sydb
Copy link
Member

sydb commented Apr 20, 2024

Sorry, I am still not convinced that having <classRef> as a child of <alternate> or <interleave> will be sufficient. So bear with me while I think this through aloud.

We are talking about references to classes that are currently expandable into one of:

  • "alternation" (( a | b | c ), the default),
  • "sequence" (( a, b, c )),
  • "sequenceOptional" (( a?, b?, c? )),
  • "sequenceRepeatable" (( a+, b+, c+)), and
  • "sequenceOptionalRepeatable" (( a*, b*, c* )).

We are planning to drop the "sequence*" possibilities because we have no mechanism of determining a good sequence or allowing a customizer to change it. But we are (or at least I am) hoping to add interleave capability. In which case we need to be able to represent the parallel structures: "interleave" (( a & b & c )), "interleaveOptional" (( a? & b? & c? )), "interleaveRepeatable" (( a+ & b+ & c+)), and "interleaveOptionalRepeatable" (( a* & b* & c* )).

I don’t think there is any way to represent those 4 possibilities just by noticing that the parent of <classRef> is <interleave>. Besides, what if I wanted an interleave of the classes, not of the elements that are members the classes? E.g., we would like the content model of <respStmt> to be

  <interleave>
    <elementRef key="resp" minOccurs="1" maxOccurs="unbounded"/>
    <classRef key="model.nameLike.agent" minOccurs="1" maxOccurs="unbounded"/>
  </interleave>

(We can’t do that, of course, because we can’t use <interleave>, as it has no equivalent in the DTD language.) That is, we want a minimum of <resp> and one of the nameLike.agent elements, not all of them.

So I think I have now convinced myself that being a child of <interleave> does not cut it. We need a tighter mechanism to specify the expansion of a class reference. (By “tighter” I mean tied closer to the class reference itself.)

@raffazizzi
Copy link
Contributor Author

raffazizzi commented Apr 29, 2024

Would it suffice to add an attribute to <interleave> to indicate the type of interleaving desired?

@raffazizzi raffazizzi self-assigned this Apr 29, 2024
@martindholmes
Copy link
Contributor

We could add an attribute to classRef:

@use="members", @use="class", or

@use="one", @use="any", or @use="all"

@tuurma
Copy link
Contributor

tuurma commented Nov 13, 2024

F2F in BA: Action on SB, JT, and RV to meet post-F2F to formalize a proposal, taking into account also #2538

@raffazizzi
Copy link
Contributor Author

raffazizzi commented Dec 3, 2024

Subgroup @sydb , @joeytakeda , @raffazizzi suggest using @org (same as the one on <attList> — value of either choice or group) to indicate how the members of a class should be organized, which will result in either <rng:alternate> or <rng:interleave>, respectively.

Introduce a new attribute potentially called @membersOccur that indicate the cardinality of each member of the class, such as single, repeatable (oneOrMore or +), optional (?), optionalRepeatable (zeroOrMore or *).

(Defaults in bold.)

@sydb
Copy link
Member

sydb commented Dec 3, 2024

Examples to clarify @raffazizzi’s summary, above …

Imagine that we have 3 classes, model.firstThree, model.midThree, and model.lastThree. The members of model.firstThree are <a>, <b>, and <c>; the members of model.midThree are <m>, <n>, and <ñ>; and the members of model.lastThree are <x>, <y>, and <z>. (Yes, I am using the Spanish alphabet because it has an odd number of letters.) Furthermore we have a 4th class, model.randFour whose members are <a>, <d>, <n>, and <r>.

We are suggesting the following. (Note that we did not discuss the pattern names at all, but they are essentially arbitrary, as they only occur in the RELAXNG schema, the user never sees them. So the names should be chosen to make debugging easier.)

class definitions

Each class gets expanded to 8 spearate patterns in the RELAX NG output. Here is what model.firstThree would look like in the compact syntax. (Remember that we are planning to get rid of classSpec/@generate, so all 8 are generated for every class, the ODD writer has no way to say “only repeatable_alternated should be usable”.)

model.firstThree_singles_interleaved            =  a  & b  & c
model.firstThree_singles_alternated             =  a  | b  | c
model.firstThree_optional_interleaved           =  a? & b? & c?
model.firstThree_optional_alternated            =  a? | b? | c?
model.firstThree_repeatable_interleaved         =  a+ & b+ & c+
model.firstThree_repeatable_alternated          =  a+ | b+ | c+
model.firstThree_optionalRepeatable_interleaved =  a* & b* & c*
model.firstThree_optionalRepeatable_alternated  =  a* | b* | c*

(For the masochists among you who prefer to see this in the XML syntax you can find it near the bottom of this comment.)

The same sort of 8 separate definitions holds for model.midThree (with "m", "n", & "ñ"), model.lastThree (with "x", "y", & "z"), and model.randFour (with "a", "d", "n", & "r"). If you want to play around with a schema that has these classes already defined, you are in luck. I have created a shell of a schema for that very purpose. Note the ".txt" extension (which is there just so gitHub will let me put it here) should probably be removed.

example one

Either of these:

<classRef key="model.firstThree"/>
<classRef key="model.firstThree" org="group" membersOccur="single"/>

would resolve to

<rng:ref name="model.firstThree_singles_interleaved"/>

example two

<classRef key="model.midThree" org="choice" membersOccur="single"/>

would resolve to

<rng:ref name="model.midThree_singles_alternated"/>

example three

<classRef key="model.lastThree" org="choice" membersOccur="optional"/>

would resolve to

<rng:ref name="model.lastThree_optionals_alternated"/>

example four

<classRef key="model.firstThree" org="group" membersOccur="repeatable" minOccurs="2" maxOccurs="3"/>

would resolve to

<rng:group>
  <rng:ref name="model.firstThree_repeatable_interleaved"/>
  <rng:ref name="model.firstThree_repeatable_interleaved"/>
  <rng:optional>
    <rng:ref name="model.firstThree_repeatable_interleaved"/>
  </rng:optional>
</rng:group>

example five

<alternate>
  <classRef key="model.firstThree" org="group" membersOccur="optionalRepeatable"/>
  <classRef key="model.midThree"   org="group" membersOccur="optionalRepeatable"/>
  <classRef key="model.lastThree"  org="group" membersOccur="optionalRepeatable"/>
</alternate>

would resolve to

<rng:choice>
  <rng:ref name="model.firstThree_optionalRepeatable_interleaved"/>
  <rng:ref name="model.midThree_optionalRepeatable_interleaved"/>
  <rng:ref name="model.lastThree_optionalRepeatable_interleaved"/>
</rng:choice>

which itself has the same effect as the following (in the compact syntax):

(
  ( a* & b* & c* )
  |
  ( m* & n* & ñ* )
  |
  ( x* & y* & z* )
)

That is,
any combination of any number of <a>, <b>, and <c> (including none of them), or
any combination of any number of <m>, <n>, and <ñ> (including none of them), or
any combination of any number of <x>, <y>, and <z> (including none of them).

So

 <a/><a/><b/><b/><b/>

would be valid, but

 <a/><y/>

would not be valid.

example six

<interleave>
  <classRef key="model.firstThree" org="choice" membersOccur="repeatable"/>
  <classRef key="model.midThree"   org="choice" membersOccur="repeatable"/>
  <classRef key="model.lastThree"  org="choice" membersOccur="repeatable"/>
</interleave>

would resolve to

<rng:interleave>
  <rng:ref name="model.firstThree_repeatable_alternated"/>
  <rng:ref name="model.midThree_repeatable_alternated"/>
  <rng:ref name="model.lastThree_repeatable_alternated"/>
</rng:interleave>

which itself has the same effect as the following (in the compact syntax):

(
  ( a+ | b+ | c+ )
  &
  ( m+ | n+ | ñ+ )
  &
  ( x+ | y+ | z+ )
)

That is a weird content model that forces the user to pick one element from each “set” (e.g., <a>, <n>, and <z>), but once chosen, each of those three elements may occur one or more times in any order.

So

    <a/><n/><z/><z/><n/><a/>

would be valid, but

    <a/><n/><z/><z/><n/><c/>

would not be valid (because it has both an <a> and a <c>, which are both from the same “set”).

example seven

<interleave minOccurs="1" maxOccurs="unbounded">
  <classRef key="model.firstThree"/>
  <classRef key="model.lastThree"/>
</interleave>

would resolve to

<rng:oneOrMore>
  <rng:interleave>
    <rng:ref name="model.firstThree_singles_alternated"/>
    <rng:ref name="model.lastThree_singles_alternated"/>
  </rng:interleave>
</rng:oneOrMore>

which itself has the same effect as the following (in the compact syntax):

(
  ( a | b | c )
  &
  ( x | y | z )
)+

Because that validates exactly the same set of documents as

(
  ( a & b & c )
  &
  ( x & y & z )
)+

the ODDism

<interleave minOccurs="1" maxOccurs="unbounded">
  <classRef key="model.firstThree" org="group"/>
  <classRef key="model.lastThree"  org="group"/>
</interleave>

is exactly the same as the example. That is, inside in <interleave> the @org attribute is kinda meaningless.

example eight

This example is just like example six but uses model.randFour instead of model.lastThree, which results in an INVALID RELAX NG schema.

<interleave>
  <classRef key="model.firstThree" org="choice" membersOccur="repeatable"/>
  <classRef key="model.midThree"   org="choice" membersOccur="repeatable"/>
  <classRef key="model.randFour"   org="choice" membersOccur="repeatable"/>
</interleave>

would resolve to

<rng:interleave>
  <rng:ref name="model.firstThree_repeatable_alternated"/>
  <rng:ref name="model.midThree_repeatable_alternated"/>
  <rng:ref name="model.randFour_repeatable_alternated"/>
</rng:interleave>

which itself has the same effect as the following (in the XML syntax with line numbers added):

01)  <rng:interleave>
02)    <rng:choice>
03)      <rng:oneOrMore>
04)        <rng:ref name="a"/>
05)      </rng:oneOrMore>
06)      <rng:oneOrMore>
07)        <rng:ref name="b"/>
08)      </rng:oneOrMore>
09)      <rng:oneOrMore>
10)        <rng:ref name="c"/>
11)      </rng:oneOrMore>
12)    </rng:choice>
13)    <rng:choice>
14)      <rng:oneOrMore>
15)        <rng:ref name="m"/>
16)      </rng:oneOrMore>
17)      <rng:oneOrMore>
18)        <rng:ref name="n"/>
19)      </rng:oneOrMore>
20)      <rng:oneOrMore>
21)        <rng:ref name="ñ"/>
22)      </rng:oneOrMore>
23)    </rng:choice>
24)    <rng:choice>
25)      <rng:oneOrMore>
26)        <rng:ref name="r"/>
27)      </rng:oneOrMore>
28)      <rng:oneOrMore>
29)        <rng:ref name="a"/>
30)      </rng:oneOrMore>
31)      <rng:oneOrMore>
32)        <rng:ref name="n"/>
33)      </rng:oneOrMore>
34)      <rng:oneOrMore>
35)        <rng:ref name="d"/>
36)      </rng:oneOrMore>
37)    </rng:choice>
38)  </rng:interleave>

which is illegal both because

  1. //rng:interleave//rng:ref[@name='a'] occurs twice (lines 04 & 29), and
  2. //rng:interleave//rng:ref[@name='n'] occurs twice (lines 18 & 32).

To my surprise, jing reports the error for "n", not for "a". Not that it matters. (I had expected it to report "a" because it occurs first. Oh well.)

In any case, Stylesheets issue #719 is for figuring out what to do with invalid RELAX NG.

bonus:
sample definition of model.firstThree in XML syntax

  <rng:define name="model.firstThree_singles_interleaved">
    <rng:interleave>
      <rng:ref name="a"/>
      <rng:ref name="b"/>
      <rng:ref name="c"/>
    </rng:interleave>
  </rng:define>
  <rng:define name="model.firstThree_singles_alternated">
    <rng:choice>
      <rng:ref name="a"/>
      <rng:ref name="b"/>
      <rng:ref name="c"/>
    </rng:choice>
  </rng:define>
  <rng:define name="model.firstThree_optional_interleaved">
    <rng:interleave>
      <rng:optional>
        <rng:ref name="a"/>
      </rng:optional>
      <rng:optional>
        <rng:ref name="b"/>
      </rng:optional>
      <rng:optional>
        <rng:ref name="c"/>
      </rng:optional>
    </rng:interleave>
  </rng:define>
  <rng:define name="model.firstThree_optional_alternated">
    <rng:choice>
      <rng:optional>
        <rng:ref name="a"/>
      </rng:optional>
      <rng:optional>
        <rng:ref name="b"/>
      </rng:optional>
      <rng:optional>
        <rng:ref name="c"/>
      </rng:optional>
    </rng:choice>
  </rng:define>
  <rng:define name="model.firstThree_repeatable_interleaved">
    <rng:interleave>
      <rng:oneOrMore>
        <rng:ref name="a"/>
      </rng:oneOrMore>
      <rng:oneOrMore>
        <rng:ref name="b"/>
      </rng:oneOrMore>
      <rng:oneOrMore>
        <rng:ref name="c"/>
      </rng:oneOrMore>
    </rng:interleave>
  </rng:define>
  <rng:define name="model.firstThree_repeatable_alternated">
    <rng:choice>
      <rng:oneOrMore>
        <rng:ref name="a"/>
      </rng:oneOrMore>
      <rng:oneOrMore>
        <rng:ref name="b"/>
      </rng:oneOrMore>
      <rng:oneOrMore>
        <rng:ref name="c"/>
      </rng:oneOrMore>
    </rng:choice>
  </rng:define>
  <rng:define name="model.firstThree_optionalRepeatable_interleaved">
    <rng:interleave>
      <rng:zeroOrMore>
        <rng:ref name="a"/>
      </rng:zeroOrMore>
      <rng:zeroOrMore>
        <rng:ref name="b"/>
      </rng:zeroOrMore>
      <rng:zeroOrMore>
        <rng:ref name="c"/>
      </rng:zeroOrMore>
    </rng:interleave>
  </rng:define>
  <rng:define name="model.firstThree_optionalRepeatable_alternated">
    <rng:choice>
      <rng:zeroOrMore>
        <rng:ref name="a"/>
      </rng:zeroOrMore>
      <rng:zeroOrMore>
        <rng:ref name="b"/>
      </rng:zeroOrMore>
      <rng:zeroOrMore>
        <rng:ref name="c"/>
      </rng:zeroOrMore>
    </rng:choice>
  </rng:define>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants