Let me elaborate the thought that new approaches to navigation might profit from a thorough appreciation of the achievements of XPath.
One of the profoundest, yet most elusive, aspects of powerful ideas is the basic *units* which they presuppose or create. Object orientation is a wonderful example, as is Functional Programming, and a negative example is the relational database system (problems caused by the lack of a unit matching domain entities, which cannot be captured without ephemeral joins).
Over abstraction leads to base entitites which are too shapeless - while in principle you might reassemble them into meaningful constructs, this reassembly is overly complex. Under abstraction leads into a clutter.
Concerning navigation, the DOM API is under abstraction. Over abstraction would be the conclusion that, given that navigation is just a mapping of locations to locations, navigation is already implemented by the flatmap() function. Better, but still over abstraction, would be the postulation of two primitives, mapping and filtering (directly supported by the Streams API functions flatmap() and filter().)
The achievement of XPath may be described as an ingenious definition of *units* giving structure to the overall operation of navigation. The "navigation is a sequence of steps" view is extremely important, but also trivial. Non-trivial, however, the model of a step, a compelling shape composed of "mapper" and "filter" subunits:
step ::= mapper filter*
mapper ::= standardMapper | customMapper
customMapper ::= expression
filter ::= expression
standardMapper ::= axisMapper axisFilter
axisMapper ::= child | descendant | ancestor | ...
axisFilter ::= nameTest | kindTest
Our two primitives - mappers and filters - are arranged into three basic units: axisMapper, axisFilter, expression. Now we can decompose navigation into two levels: level#1 steps, level#2 the step components (axis, node test and predicates). The reduction of complexity is so successful, as the technical model matches our mental model of navigation closely.
Concerning the Streams API - it is a highly encouraging fact that the key abstractions of navigation - mapping, filtering, chaining - are key abstractions of the API itself (flatmap(), filter(), stream-in-stream-out model). But here come the crossroads: will the emerging navigation API follow XPath in the recognition of a unit "step" which is *ABOVE* the primitives mapper and filter? Looking again at your explorative example:
N.walk(Axis.child("city")).map(Axis.attValue("name"))
a step model is not yet quite obvious. Interesting, here, also your concern with syntax, which reveals to the eye step units otherwise obfuscated by syntactical clutter.
Michael Kay <mike@saxonica.com> schrieb am 17:25 Freitag, 23.Juni 2017:
As the expressiveness of XPath is excellent (and I think - not to be surpassed),
Well there are certainly some improvements that one could contemplate:
* Separating positional filters from boolean filters so they are syntactically distinct
* A clearer separation between the "/" and "!" operators
* A more orthogonal set of axes, e.g. allowing an "or-self" modifier with any base axis
* Representing attributes using maps rather than as nodes
But yes, the basic model is pretty sound. Axes are functions from nodes to sequences of nodes, the "!" operator is a flatMap() operator, "/" is flatMap followed by deduplication and sorting-into-document-order, boolean predicates a pure filter() operation.
A lot of the messier things come from lack of orthogonality and unnecessary complexity in the data model (notoriously namespaces) and XPath does a pretty good job at smoothing over some terrible cracks.
Michael Kay
Saxonica
any fresh attempt at a navigation model might profit from a comparison of its key principles with the key principles behind XPath. I would summarize the latter as follows:
(1) Navigation is a sequence of steps.
(2) A step is a mapping of current locations to next loations.
(3) A step is either a standard step or a custom step.
(4) A standard step has a direction (axis) and a simple standardized filter (node name or kind).
(5) A step can be extended by custom filters.
(6) The addition of step filters does not increase the complexity of the navigation.
(7) Step semantics are self-contained and any step can be applied to any input
(2) A great challenge - and perhaps a hopeless one - would be to create an expressiveness which could at least be a far cry of what XPath offers. It is strange to say
N.walk(Axis.child("city")).flatMap(Axis.attribute("name").map(Node::stringValue)
when what you really want to say is
city/@name
Excellent point. However, dropping into another language does have all sorts of disadvantages: apart from the learning issues, there's the lack of compile-time syntax checking and type checking, the cost of dynamic compilation/interpretation, etc.
One thing to look at, perhaps, is how it translates into Scala, where you can define your own operators:
A.flatMap(B) --> A/B
A.attribute(B) --> A @ B
etc; and then we start to have something very XPath-like, but with a syntax that's compiled and validated by the host language.