Skip to content

2073 data model changes for JNodes and Sequences - #2160

Closed
michaelhkay wants to merge 1 commit into
qt4cg:masterfrom
michaelhkay:2073-jnodes-and-sequences
Closed

michaelhkay wants to merge 1 commit into
qt4cg:masterfrom
michaelhkay:2073-jnodes-and-sequences

Conversation

@michaelhkay

Copy link
Copy Markdown
Contributor

This is a first draft of a PR, giving the data model changes only, for a change to the JNode model affecting maps and arrays with sequence-valued entries. A sequence of length 2 or more now has children representing the items in the sequence. Although there is still an asymmetry between sequences of length 1 and longer sequences, it is more manageable than i the previous model.

@michaelhkay
michaelhkay marked this pull request as draft August 12, 2025 14:59
</tbody>
</table>

<note><p>Sequences of length 2 or more have children; sequences of length 0 or 1 have none.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this wording correct/clear enough, given that a sequence of a single array can have children?

Possible variant:

  • Sequences of length 2 or more have only children with the kind "sequence"; sequences of length 1 have no children with the kind "sequence" (but can have other kinds); sequences of length 0 have no children.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the note can be improved. In fact, I am currently exploring a revision in which sequences of length 1 do have children, unless they are themselves children of a sequence of length 1.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently exploring a revision in which sequences of length 1 do have children, unless they are themselves children of a sequence of length 1.

Excellent idea. Although, it seem the set of conditions should be different.

  • The JNode of ( 10, 20, 30) has children: 10 20 30, each of which should have no child.
  • The JNode of ( 10 ) should have no child if the parent is a sequence, or, otherwise, child 10.

@benibela

Copy link
Copy Markdown

Wasn't it originally the plan in xquery version 4.0 not to change the data model and to only make changes in version 5.0?

@michaelhkay

Copy link
Copy Markdown
Contributor Author

Wasn't it originally the plan in xquery version 4.0 not to change the data model and to only make changes in version 5.0?

Indeed, I resisted making changes to the data model for a long time, before finally coming to the conclusion that JNodes gave us a much more powerful way of handling trees of maps and arrays.

@ruv ruv mentioned this pull request Aug 12, 2025
@michaelhkay

Copy link
Copy Markdown
Contributor Author

The JNode of ( 10 ) should have no child if the parent is a sequence, or, otherwise, child 10.

The main problem with this seems to be that the descendant axis will include two nodes with the content 10.

@ruv

ruv commented Aug 13, 2025

Copy link
Copy Markdown
Contributor

The main problem with this seems to be that the descendant axis will include two nodes with the content 10.

Yes, this can be confusing at the first glance, but I'm not sure this is a problem.

Conceptually, the content of the first node is (10, () ) and the content of its child is 10. Their content are equal simply because sequences are not nestable: 10 = (10) = (10, () ) = ((10, () )).

Rationale: if a sequence can have 1, 2, or 3 atomic items, there should be a path to the first item that is the same regardless whether the second and third item are provided.

@michaelhkay

Copy link
Copy Markdown
Contributor Author

Rationale: if a sequence can have 1, 2, or 3 atomic items, there should be a path to the first item that is the same regardless whether the second and third item are provided.

Yes, that's obviously desirable, but at the moment I don't see a way to make it work without making things like sum([(1,2), (3)]//type(xs:integer)) produce crazy answers.

@ruv

ruv commented Aug 13, 2025 •

Copy link
Copy Markdown
Contributor

at the moment I don't see a way to make it work without making things like sum([(1,2), (3)]//type(xs:integer)) produce crazy answers.

Good example. Conceptually, for such an operation we should select only leaves:
sum( [(1,2), (3)]//type(xs:integer)[not(*)] )

Currently, the content of a JNode contains information about the entire subtree (which starts with that node). So there will always be cases where we can get multiple copies of the same atomic item. For example:

 [  [1,2, [3] ], [4, [5,6] ] // jnode(*, array(*)) / array:flatten(.) => sum()

An alternative approach is to introduce the head:: axis, which means the head of the sequence.
The first satisfied point applies:

  • if the node content is empty, head:: is empty;
  • if child:: is not empty, head:: contains the first node from it;
  • (optionally) if the node kind is "sequence", head:: is empty;
  • otherwise, head:: contains the node whose content is the same as in this node, whose parent is this node, whose kind is "sequence", and whose selector is 1;
    • rationale: the depth of the node in head:: should be the same regardless of siblings.
    • NB: the point (3) still does not hold.

So, if we need to access the first item in a sequence regardless of the other siblings, we can use head::.

@Arithmeticus Arithmeticus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the PR is on the agenda for today's QT4 meeting, so I have added some comments. Apologies if revisions are still underway, and my comments are premature.

</tbody>
</table>

<note><p>Sequences of length 2 or more have children; sequences of length 0 or 1 have none.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggled to understand this sentence. I think this is what is meant: "JNodes whose content is a sequence of two or more items have children; those whose content is a sequence of zero or one item have none."

Or maybe this: "If a JNode's content is a single map with more than one map entry, or it is a single array with more than one array member, or it is a sequence of two or more items, then that JNode has children; otherwise it has none."

Needs clarification.


<note><p>Sequences of length 2 or more have children; sequences of length 0 or 1 have none.
The reason for this is to ensure that the tree of JNodes is always finite.
This can make processing a little difficult in a structure where it is sensible to treat

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "solution" on line 6400 seems to point back to "processing" on 6397, but the developer is not responsible for such processing. So is this note intended only for those responsible for writing implementations? Unclear audience.

This can make processing a little difficult in a structure where it is sensible to treat
a sequence in the same way regardless of its length (for example, the authors of a book).
One solution is to use the <code>descendant</code> axis in place of the <code>child</code>
axis. Another solution is to use the <code>child-plus</code> axis which expands sequences of

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is a "child-plus" axis?

</tbody>
</table>

<note><p>Sequences of length 2 or more have children; sequences of length 0 or 1 have none.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Help me understand one implication. Consider the example, where R's J1 is "a" : 1. If J1 were redefined as "a" : map{ "a1" : 1, "a2" : 2} then J1 would have content map{ "a1" : 1, "a2" : 2} and kind "map" and selector "a" and parent R and children (). That is, it would be identical to existing J1. Because the content is a sequence of only one item, it has no children ("Sequences of length 2 or more have children; sequences of length 0 or 1 have none."). But that seems counterintuitive. I would expect a single child J11. See other comments where I express confusion over whether and when a singleton array or singleton map is shallow skipped.

Another implication is that a children field in a JNode will never have exactly 1 JNode. It has either zero or two or more.

<item><p><term>·position·</term> is 1.</p></item>
<item><p><term>·kind·</term> is <code>"array"</code>.</p></item>
<item><p><term>·selector·</term> is 2.</p></item>
<item><p>The <emph>dm:j-children</emph> accessor returns a sequence of four

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, because there isn't a parallel list item that discusses ·children·, but only a reference to a function, the implication is that there is not a property called children. But the table in the full example below makes ·children· a property on the same level as the other JNode properties. This needs some consistency/clarity.

Also, I cannot locate anything in the specs that explains the rules for the dm:j-children accessor. I want to check, for example, if a JNode's content is a single map or array, if the dm:j-children accessor shallow skips the array or map wrapper to get straight at the array members or map entries. (See below.)

is given by the <term>·selector·</term> property).</p></item>
</ulist>

<p><termdef id="dt-j-children" term="j-children">The accessor <code>j-children</code>, applied to a JNode <var>$P</var>, returns a sequence

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phraseology implies that there is not a ·children· property, contra example exposition below. Does a JNode have a ·children· property?

<td><code>"map"</code></td>
<td><code>"c"</code></td>
<td><var>R</var></td>
<td><var>J/31</var>, <var>J/32</var></td>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the implication is that dm:j-children shallow-skips a single map or single array and makes its map entries or array members direct children? Just checking.

"d": (10, [20, 30]),
"e": (<p/>, <q/>)
}]]></eg></td>
<td>()</td>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "map". The rules above specify this property cannot be empty.

@ChristianGruen ChristianGruen added the Blocked PR is blocked (has merge conflicts, doesn't format, etc.) label Oct 15, 2025
@michaelhkay michaelhkay added Abandoned PR was rejected, withdrawn, or superseded and removed Blocked PR is blocked (has merge conflicts, doesn't format, etc.) labels Aug 27, 2026
@michaelhkay

Copy link
Copy Markdown
Contributor Author

Superseded by #2878

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Abandoned PR was rejected, withdrawn, or superseded

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants