[XML-DEV Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

An XML API using Java streams

  • From: Michael Kay <mike@saxonica.com>
  • To: XML Developers List <xml-dev@lists.xml.org>
  • Date: Tue, 20 Jun 2017 09:51:08 +0100

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]


PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
 

Stylus Studio has published XML-DEV in RSS and ATOM formats, enabling users to easily subcribe to the list from their preferred news reader application.


Stylus Studio Sponsored Links are added links designed to provide related and additional information to the visitors of this website. they were not included by the author in the initial post. To view the content without the Sponsor Links please click here.

Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.