N5Reader.getAttribute(String group, String key, Class class).
These basics are described in the N5 API Basics Tutorial. In this tutorial, we will show that methods accept more sophisticated expressions for the key that we call “attribute paths.” These enable you to set and access any part of the attribute hierarchy.
Arrays
We’ll start by discussing array attribute indexing. First make some array attribute:
Code
var n5 =newN5Factory().openWriter("attribute-demo.n5");var group ="arrayDemo";n5.createGroup(group);n5.setAttribute(group,"array",newdouble[]{5,6,7,8});Arrays.toString(n5.getAttribute(group,"array",double[].class));
[5.0, 6.0, 7.0, 8.0]
Individual elements of the array can be retrieved by adding [i] after the key, where i is an integer (zero-based indexing). N5 will return null for indexes outside the bounds of the array, including for negative values.
N5’s setAttribute will always do what is requested when possible, even if it will overwrite data. If safety is necessary, developers should manually check if an attribute key is present. Use of the type JsonElement type is the most safe, because a non-null JsonElement will be returned if data of any type is present at the requested key.
Code
// overwrite the previous arrayn5.setAttribute(group,"array",newString[]{"destroy"});// array is now [ "destroy" ]Arrays.toString(n5.getAttribute(group,"array",String[].class));
[destroy]
Code
if( n5.getAttribute( group,"array", JsonElement.class)==null) n5.setAttribute(group,"array",newString[]{});// array is still [ "destroy" ]Arrays.toString(n5.getAttribute(group,"array",String[].class));
[destroy]
Objects
JSON objects are structures with “fields” that can be referenced by their String name. One way to set objects is by using a Map.
Code
var group ="objectDemo";n5.createGroup(group);var a =Collections.singletonMap("a","A");n5.setAttribute(group,"obj", a );n5.getAttribute(group,"obj",Map.class);
{a=A}
The value for an object’s field can be any type, even another object. Individual fields for an object can be accessed by appending /<field-name> to the attribute name. For example:
Code
var b =Collections.singletonMap("b","B");// set the value of obj/a to {b=B}n5.setAttribute(group,"obj/a", b);n5.getAttribute(group,"obj",Map.class);
{a={b=B}}
Code
n5.getAttribute(group,"obj/a",Map.class);
{b=B}
Notice that it is possible to repeatedly access subfields of nested objects. In fact, the set of all attributes in an N5 group is usually itself an object! We call it the “root object” and access it with the the key "/"
Code
n5.getAttribute(group,"/",Map.class);
{obj={a={b=B}}}
For the following examples, we’ll use the class Pet defined here:
Code
class Pet {String name;int age;publicPet(String name,int age){this.name= name;this.age= age;}publicStringtoString(){returnString.format("pet %s is %d", name, age);}}
Code
n5.setAttribute(group,"pet",newPet("Pluto",93));Pet pet = n5.getAttribute(group,"pet", Pet.class);pet
This example sets the value of an integer inside several nested arrays and objects.
Note: When indexing an array, the path separators / before and after the index operator [ ] are optional
Code
// remove all attributes n5.removeAttribute(group,"/");n5.setAttribute(group,"one/[2]/three/[4]",5);n5.setAttribute(group,"one[2]three[0]",12);n5.getAttribute(group,"/", JsonElement.class);
{"one":[null,null,{"three":[12,0,0,0,5]}]}
Removing attributes and dealing with nulls
We saw about that removeAttribute can be used to remove attributes. The first variant takes the group and attribute key as arguments, and returns nothing after removal. The second variant also takes a Class argument and will return the removed object of type T if possible. If the value of the attribute cannot be parsed into the requested type, the attribute will not be removed, even if the key exists.
Code
var group ="animals";n5.createGroup(group);n5.setAttribute(group,"cow","moo");n5.setAttribute(group,"dog","woof");n5.setAttribute(group,"sheep","baa");n5.getAttribute(group,"/", JsonElement.class);
// throws an exception because the value of "sheep" is not an inttry{ n5.removeAttribute(group,"sheep",int.class);}catch(N5Exception e ){System.err.println("An exception was thrown");}// observe that the attribute was not removedn5.getAttribute(group,"/", JsonElement.class);
An exception was thrown
{"sheep":"baa"}
Warning
In the default implemenation, setting the value of an attribute to null will remove that attribute (i.e. the attribute’s key will be removed).
However, we strongly recommended using the removeAttribute methods when removing attributes, since setting an attribute to null can lead to inconsistent behaviour, depending on how the N5Writer was created (see below).
Setting an attribute path to null can even result in creating attributes along the path, regardless of whether serializeNulls is enabled or not.
In cases where it is useful to write the value null into the attributes, you must create an N5Writer using a GsonBuilder with serializeNulls enabled. This example writes a null value to the key "attr".
Code
var n5WithNulls =newN5Factory().gsonBuilder(newGsonBuilder().serializeNulls()).openWriter("attribute-demo.n5");n5WithNulls.setAttribute(group,"attr",null);n5WithNulls.getAttribute(group,"/", JsonElement.class);
{"sheep":"baa","attr":null}
Keys are paths
Think about keys as paths into a hierarchy, where / separates levels of the hierarchy. Attribute methods support relative paths, where . refers to “this” path, and .. refers to the parent path.
Code
var group ="details";n5.createGroup(group);n5.setAttribute(group,"a/b/c","tutorial");n5.getAttribute(group,"/", JsonElement.class);
{"a":{"b":{"c":"tutorial"}}}
The key a/. is equivalent to a
Code
n5.getAttribute(group,"a/.", JsonElement.class);
{"b":{"c":"tutorial"}}
Code
n5.getAttribute(group,"a/..", JsonElement.class);
{"a":{"b":{"c":"tutorial"}}}
The parent of an array element refers to the array:
We strongly recommend against using / or \ in key names. Similarly, . or .. should not be used in between forward slashes, i.e. avoid (/../ or /./ in key names).
While we recommend against it, is it possible to use forward slash (/) or backslash (\) as field names for attributes. Since / is reserved to refer to the root attribute, it must be escaped with a backslash to refer to the literal string "/".
The code below is not suitable for children, or anyone.
Code
var group ="warnings";n5.createGroup(group);n5.setAttribute(group,"\\/","Please don't do this");n5.setAttribute(group,"\\","UGH");n5.setAttribute(group,".","what does this mean!?");n5.setAttribute(group,"..\\/.","...pain...");n5.getAttribute(group,"/", JsonElement.class);
{"/":"Please don't do this","\\":"UGH",".":"what does this mean!?","../.":"...pain..."}