XML.orgXML.org
FOCUS AREAS |XML-DEV |XML.org DAILY NEWSLINK |REGISTRY |RESOURCES |ABOUT
OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index]
An XML API using Java streams

I'm struck how 95% of Java/XML users still seem to be stuck on DOM navigation, perhaps with a bit of XPath thrown in, which all seems a terribly late-20th-century way of doing things. The success of jQuery in the Javascript world, and the emergence of the Java Streams API, suggests there ought to be a better way. I don't know if anyone has done this before, but I thought I'd sketch out some ideas. (I have to say me experience with the Streams API is pretty cursory, to coin a phrase, so there may well be better ways of doing things that I've missed.

In particular:

(a) It would be nice to navigate using functional stream-based interfaces rather than procedural step-by-step navigation

(b) It would be nice to do all the navigation using Java primitives without requiring XPath as a separate interpreted sub-language.

Navigation is basically a question of constructing streams of nodes. Let's start by defining the XPath axes as functions (Node -> Stream(Node)). For example, given a node N, Axis.child(N) returns a stream containing the children of N.

If we define Node.walk(F) as returning a stream that navigates using the supplied function F, then

N.walk(Axis::child)

gets the children of N (you could write Axis.child(N) if you prefer), while

N.walk(Axis::child).flatMap(Axis::child)

gets the grandchildren.

If we define NodeTest::isElement as a function that returns true if the argument is an element node, then

N.walk(Axis::child).filter(NodeTest::isElement)

returns a stream of child nodes that are elements.

If we want to match nodes with a specific local name, then NodeTest.withLocalName(String) returns a function that returns true for nodes having that local name, so we can write

N.walk(Axis::child).filter(NodeTest.withLocalName("city"))

This is getting a bit long-winded for a simple task, so perhaps Axis.child(N) should return a function that navigates the child axis and filters by name, so the above becomes

N.walk(Axis.child("city"))

If Node.stringValue() returns the string value of a node

N.walk(Axis.child("city")).flatMap(Axis.attribute("name").map(Node::stringValue)

returns the names of the child cities (as a Stream<String>).

Perhaps there's a shortcut for this:

N.walk(Axis.child("city")).map(Axis.attValue("name"))

And then we could add tree construction using function chaining, e.g.

element("cities")
  .addChild(element("city").addAttribute("name", "Rome"))
  .addChild(element("city").addAttribute("name", "Paris"))

=====

Just an initial sketch of some ideas. Does it seem worth pursuing?

Michael Kay
Saxonica


[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index]


News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 1993-2007 XML.org. This site is hosted by OASIS