Since version 7.2 Camunda provides an optional library which is called Camunda Spin. Spin is a lightweight wrapper library which provides a easy to use API when working with text based data formats such as XML and JSON.
Example
<?xml version="1.0" encoding="UTF-8" ?>
<show>
<name>The Big Bang Theory</name>
<totalseasons>8</totalseasons>
<episodelist>
<season no="1">
<episode>
<epnum>1</epnum>
<seasonnum>01</seasonnum>
<prodnum>276023</prodnum>
<airdate>2007-09-24</airdate>
<link>https://www.tvrage.com/The_Big_Bang_Theory/episodes/550436</link>
<title>Pilot</title>
</episode>
<episode>
<epnum>2</epnum>
<seasonnum>02</seasonnum>
<prodnum>3T6601</prodnum>
<airdate>2007-10-01</airdate>
<link>https://www.tvrage.com/The_Big_Bang_Theory/episodes/603610</link>
<title>The Big Bran Hypothesis</title>
</episode>
...
As Output we want to obtain a JSON list of all episodes which aired after 2012:
[{
"name":"The Shiny Trinket Maneuver",
"air-date":"2012-01-12"
},
{
"name":"The Recombination Hypothesis",
"air-date":"2012-01-19"
}, ... ]
Enable Spin in your project
In order to enable Camunda Spin in your project,
1) add it to your maven dependencies:
<dependencymanagement>
<dependencies>
<dependency>
<groupid>org.camunda.bpm</groupid>
<artifactid>camunda-bom</artifactid>
<version>7.3.0-alpha1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencymanagement>
<dependencies>
<dependency>
<groupid>org.camunda.spin</groupid>
<artifactid>camunda-spin-core</artifactid>
</dependency>
<dependency>
<groupid>org.camunda.spin</groupid>
<artifactid>camunda-spin-dataformat-json-jackson</artifactid>
</dependency>
<dependency>
<groupid>org.camunda.spin</groupid>
<artifactid>camunda-spin-dataformat-xml-dom</artifactid>
</dependency>
</dependencies>
2) In your Java Code, add the following static import:
import static org.camunda.spin.Spin.*;
Parsing the Xml input with Spin
XML(xmlInput)
The Java 6/7 way
Using Spin’s xPath function to iterate through all episodes
for (SpinXmlElement element : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {
// work with the element
}
Getting the production Year as Integer
for (SpinXmlElement element : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {
int productionYear = Integer.parseInt(element.childElement("airdate").textContent().substring(0, 4));
}
Creating an empty JSON Document
SpinJsonNode resultJson = JSON("[]");
Transform the Episodes into JSON
Next we create a JSON object into which we copy the values from the xml source:
SpinJsonNode episodeJson = JSON("{}")
.prop("name", episode.childElement("title").textContent())
.prop("air-date", episode.childElement("airdate").textContent());
The complete Java 6/7 source code then looks like this:
SpinJsonNode resultJson = JSON("[]");
for (SpinXmlElement episode : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {
int productionYear = Integer.parseInt(episode.childElement("airdate").textContent().substring(0, 4));
if(productionYear >= 2012) {
SpinJsonNode episodeJson = JSON("{}")
.prop("name", episode.childElement("title").textContent())
.prop("air-date", episode.childElement("airdate").textContent());
resultJson.append(episodeJson);
}
}
The Java 8 Way
Java 8 introduces the Stream API and lambdas. This allows us to write a very compact representation for obtaining the same thing:
final SpinJsonNode resultJson = JSON("[]");
XML(xmlInput)
.xPath("/Show/Episodelist/Season/episode").elementList()
.stream()
.filter(e -> Integer.parseInt(e.childElement("airdate").textContent().substring(0, 4)) >= 2012)
.map(e -> JSON("{}")
.prop("name", e.childElement("title").textContent())
.prop("air-date", e.childElement("airdate").textContent()))
.forEach(e -> resultJson.append(e));
What is missing?
The above example is not “purely” functional. In the forEach
method we collect the generated customers and append them to the resultJson
object.
A more functional approach would use a java.util.stream.Collector
:
SpinJsonNode resultJson = XML(xmlInput)
.xPath("/Show/Episodelist/Season/episode").elementList()
.stream()
.filter(e -> Integer.parseInt(e.childElement("airdate").textContent().substring(0, 4)) >= 2012)
.map(e -> JSON("{}")
.prop("name", e.childElement("title").textContent())
.prop("air-date", e.childElement("airdate").textContent()))
.collect(asJsonList());
The SpinCollectors.asJsonList()
method does not exist yet. This would be something the Spin library could provide. In case anybody would use this?