Map YAML to Data, and Back. In Java.
The YAMLSourceMap provides a mapping between locations in a YAML document (the source) and the data values created from the YAML document.
The mapping works in both directions.
If you have a location in the YAML document, the source map tells you the address (JSON pointer) of the data value this location relates to.
If you have a JSON pointer for some data created from the YAML document the source map tells you the locations in the YAML document that created the data.
As YAML is a superset of JSON the YAMLSourceMap can also be used to create source maps for JSON documents.
The central type of this module is the YAMLSourceMap. You create a YAMLSourceMap for a specific YAML document using the YAMLSourceMapAPI. Either you specify a Reader to read the YAML text from:
Reader reader = ...;
YAMLSourceMap srcMap = YAMLSourceMapAPI.createYAMLSourceMap(reader);
or directly pass in the YAML text:
String yamlText = "foo: 123\nbar: 456\n";
YAMLSourceMap srcMap = YAMLSourceMapAPI.createYAMLSourceMap(yamlText);
Once you have the YAMLSourceMap you can pass in a location in the YAML document text and the source map gives you the address of the data (value) the text at the given location in the YAML document created.
The data address is given as a JSON Pointer 1, a standard format to identify a specific value in a JSON document.
You can either specify the location in the YAML text as an offset to the start of the text:
YAMLSourceMap srcMap =...;
int offset = 42;
String jsonPointer = srcMap.jsonPointerAtOffset(offset); // return e.g. "/bill-to/address"
or give the location by line and column. E.g. to get the JSON Pointer for the text of column 14 of the third line you would write:
YAMLSourceMap srcMap =...;
String jsonPointer = srcMap.jsonPointerAtLocation(3, 14); // return e.g. "/bill-to/address"
To get from some data value to the corresponding YAML document text use
YAMLSourceMap.sourceRangeOfPointer(java.lang.String)
.
Pass in a JSON Pointer and the method gives you the range in the YAML text
related to the data value. This may also include surrounding whitespaces
or comments, or special characters like ":", "[" etc.):
YAMLSourceMap srcMap =...;
String jsonPointer = "/bill-to/address";
YAMLRange range = srcMap.sourceRangeOfPointer(jsonPointer);
If you interested just in the text range that defines the data value
you can use the method YAMLSourceMap.sourceRangeOfValueOfJsonPointer(...)
:
YAMLSourceMap srcMap =...;
String jsonPointer = "/bill-to/address";
YAMLRange range = srcMap.sourceRangeOfValueOfJsonPointer(jsonPointer);
The following picture demonstrates the difference between
sourceRangeOfJsonPointer
and sourceRangeOfValueOfJsonPointer
for the example
JSON Pointer /bill-to/address
.
As you can see sourceRangeOfJsonPointer
also includes white spaces
and the map item's key "address:
", but sourceRangeOfValueOfJsonPointer
just the range directly defining the value for JSON Pointer "/bill-to/address
".
The methods jsonPointerAtOffset
, jsonPointerAtLocation
sourceRangeOfJsonPointer
, and sourceRangeOfValueOfJsonPointer
cover
the basic cases you may want to use a YAMLSourceMap for.
In addition, the YAMLSourceMap also provides the FragmentsAPI
that
gives you a more detailed mapping between the YAML text and its data.
As the name suggests the central idea here are "fragments".
Fragments partition the whole YAML text into non-overlapping ranges. Each fragment covers a range of characters that share the same data (address), i.e. the same JSON pointer. Additionally, a fragment is of a certain kind describes what sort of elements in the YAML document a fragment related to.
Beside the kinds known from the JSON data model (scalar, sequence, map)
other kinds exist that refine these basic kinds, to cover "sub aspects".
E.g. for a map the kinds MAP_KEY
and MAP_VALUE
define subranges within
the map entry's definition.
This additional information gives you many options for your applications. E.g. assume you want to use a YAMLSourceMap to implement some content assist feature when editing a YAML document. With the fragments it is easy to display different assists e.g. for the key vs. the value of a map item. Or you can even show different assists depending on where in a map's key the user has the text cursor.
The following picture shows the available fragment kinds and how they relate to (a sample) YAML text.
Typically, a given JSON pointer relates to multiple fragments,
of different kinds. E.g. in the picture above the first three
green fragments all map to JSON pointer /invoice
.
For more details please see the JavaDoc of the FragmentAPI or
the FragmentKindColorCodingApp
in the examples.
Have a look at the module abego-yaml-sourcemap-examples
for some examples how
the YAMLSourceMap can be used in an application.
E.g. the "Breadcrumbs" application demonstrates how to use the YAMLSourceMap to implement a "Breadcrumbs bar" (/Navigation bar), e.g. to view YAML/JSON documents.
That application is also a use case for "bidirectional mapping":
- After a click in the YAML text (the source) the source map provides the address of the data created by the text at the click location. The Breadcrumbs bar then displays the parts of this address/JSON Pointer as breadcrumbs. (YAML Text -> Data)
- Clicking a breadcrumb in the Breadcrumbs bar navigates the text cursor in the YAML text to the location corresponding to that breadcrumb. (Every breadcrumb actually is a JSON Pointer). The source map provides the proper location for every given JSON Pointer/breadcrumb. (Data -> YAML Text)
BTW: the "Breadcrumbs" application also highlights the source ranges of the YAML entity located at the text cursor position, both the "full" source range and the "value" source range. For details on the difference see chapter Find the YAML/JSON document text that created a data value.
Maven:
To use YAMLSourceMap in a project built with Maven, add the following to the element in your pom.xml file.
<dependency>
<artifactId>abego-yaml-sourcemap-core</artifactId>
<groupId>org.abego.yaml</groupId>
<version>1.0.1</version>
</dependency>
Download: https://github.com/abego/yaml-sourcemap/releases/tag/v1.0.1
You may check out the source code from the GitHub repository.
- Sources: https://github.com/abego/yaml-sourcemap
- Twitter: @abego (e.g. for announcements of new releases)
YAMLSourceMap is available under a business friendly MIT license.