Repository: scipp/scippneutron

Issue:
JSONGroup/JSONDataset not compatible with the latest json nexus template.
It is not compatible with the latest json nexus templates.

For example,
https://github.com/scipp/scippneutron/blob/0988a279a8b2fc480bca867bdc4a06233d0e4e2b/tests/io/json_nexus_examples/entry.json#L1-L24

Now looks like:
```json
{
  "children": [{
      "name": "entry",
      "type": "group",
      "attributes": [{ "name": "NX_class", "dtype": "string", "values": "NXentry"}],
      "children": [{
          "module": "dataset",
          "config": { "name": "title", "values": "$TITLE$", "type": "string"}
        }]
    }]
}
```

We should make it compatible and update the examples.

Discussion:
jokasimr: I think there are some things left to do here:
I added a test for loading the ymir instrument description from gitlab, this is what we will need to load in beamlime (is that right?), but the test does not pass yet.
The test was marked as skipped because I thought the test failure was related to the other skipped test with the skip message: `Stream handling with log not implemented`, but now I'm not sure that it is.

The test fails with the message:
```
UserWarning: Failed to load /entry/instrument/laser_monitor as NXmonitor: Signal is not an array-like.
```
not sure what the issue is there, but it seems like either
 * something about the `laser_monitor` group doesn't conform to our idea of a `NXmonitor`
 * or something about the way the structure is handled by the json loader is not correct and that causes the error.
 
Do you have an idea about what the issue might be @SimonHeybrock ?
 


SimonHeybrock: > I think there might be one thing left to fix here: I added a test for loading the ymir instrument description from gitlab, this is what we will need to load in beamlime (is that right?),

I think we will mainly be using Loki.

> but the test does not pass yet. The test was initially marked as skipped because I thought the test failure was related to the other skipped test with the skip message: `Stream handling with log not implemented`, but I'm not sure that it is.
> 
> The test fails with the message:
> 
> ```
> UserWarning: Failed to load /entry/instrument/laser_monitor as NXmonitor: Signal is not an array-like.
> ```
> 
> not sure what the issue is there, but it seems like either
> 
>     * something about the `laser_monitor` group doesn't conform to our idea of a `NXmonitor`
> 
>     * or something about the way the structure is handled by the json loader is not correct and that causes the error.
> 
> 
> Do you have an idea about what the issue might be @SimonHeybrock ?

This sounds like a problem in either ScippNexus or the file, not the JSON adapter.
SimonHeybrock: > > I think we will mainly be using Loki.
> 
> I didn't mean the `ymir.json` file specifically, just that we will need to read instrument descriptions like those in the gitlab repo. For the record, loading the `loki.json` file fails with a similar error message:
> 
> ```
> UserWarning: Failed to load /entry/instrument/loki_detector_0 as NXdetector: Signal is not an array-like.
> ```
> 
> > This sounds like a problem in either ScippNexus or the file, not the JSON adapter.
> 
> Okay then I'll mark the test as TODO and leave it as it is right now.

Actually you simply need to ignore the warning. The loading actually works, it is just a fallback that issues a warning. Since we have strict warning policies (tests fail if there are warnings), you have to allow this warning in this test.
jokasimr: > Actually you simply need to ignore the warning. 

:+1: 

Patch:
diff --git a/src/scippneutron/io/nexus/_json_nexus.py b/src/scippneutron/io/nexus/_json_nexus.py
index 17e2f3ef..bed10d41 100644
--- a/src/scippneutron/io/nexus/_json_nexus.py
+++ b/src/scippneutron/io/nexus/_json_nexus.py
@@ -8,7 +8,6 @@ from dataclasses import dataclass
 from typing import Any, Dict, List, Tuple, Union
 
 import numpy as np
-from scippnexus.typing import H5Group
 
 _nexus_class = "NX_class"
 _nexus_units = "units"
@@ -16,6 +15,7 @@ _nexus_name = "name"
 _nexus_path = "path"
 _nexus_values = "values"
 _nexus_dataset = "dataset"
+_nexus_config = "config"
 _nexus_group = "group"
 _nexus_children = "children"
 _nexus_link = "link"
@@ -87,12 +87,13 @@ def make_json_dataset(name: str, data) -> dict:
             "size": data.shape,
             "type": numpy_to_filewriter_type[data.dtype.type],
         }
-
     return {
-        "type": "dataset",
-        "name": name,
-        "values": data,
-        "dataset": dataset_info,
+        'module': _nexus_dataset,
+        _nexus_config: {
+            **dataset_info,
+            _nexus_name: name,
+            _nexus_values: data,
+        },
         "attributes": [],
     }
 
@@ -117,100 +118,43 @@ def _get_attribute_value(
     raise MissingAttribute
 
 
-class _Node(dict):
-    def __init__(self, parent: dict, name: str, file: dict, group: dict):
-        super().__init__(**group)
-        self.parent = parent
-        self.name = name
-        self.file = file
+def _visitnodes(root: Dict):
+    for child in root.get(_nexus_children, ()):
+        yield child
+        yield from _visitnodes(child)
 
 
-def _visit_nodes(
-    root: Dict,
-    group: Dict,
-    nx_class_names: Tuple[str, ...],
-    groups_with_requested_nx_class: Dict[str, List[H5Group]],
-    path: List[str],
-):
-    try:
-        for child in group[_nexus_children]:
-            try:
-                path.append(child[_nexus_name])
-            except KeyError:
-                # If the object doesn't have a name it can't be a NeXus
-                # class we are looking for, nor can it be a group
-                # containing a NeXus class we are looking for, so skip to
-                # next object
-                continue
-            try:
-                nx_class = _get_attribute_value(child, _nexus_class)
-                if nx_class in nx_class_names:
-                    groups_with_requested_nx_class[nx_class].append(
-                        _Node(group=child, parent=group, name="/".join(path), file=root)
-                    )
-            except MissingAttribute:
-                # It may be a group but not an NX_class,
-                # that's fine, continue to its children
-                pass
-            _visit_nodes(
-                root, child, nx_class_names, groups_with_requested_nx_class, path
-            )
-            path.pop(-1)
-    except KeyError:
-        pass
+def _name(node: Dict):
+    if _nexus_name in node:
+        return node[_nexus_name]
+    if _nexus_config in node:
+        return node[_nexus_config][_nexus_name]
+    return ''
 
 
-def contains_stream(group: Dict) -> bool:
-    """
-    Return True if the group contains a stream object
-    """
-    if not isinstance(group, JSONGroup):
-        return False
-    try:
-        for child in group._node[_nexus_children]:
-            try:
-                if child["type"] == _nexus_stream:
-                    return True
-            except KeyError:
-                # "type" field ought to exist, but if it does
-                # not then assume it is not a stream
-                pass
-    except KeyError:
-        # "children" field may be missing, that is okay
-        # but means this this group cannot contain a stream
-        pass
-    return False
+def _is_group(node: Dict):
+    return _nexus_children in node
 
 
-def _find_by_type(type_name: str, root: Dict) -> List[H5Group]:
-    """
-    Finds objects with the requested "type" value
-    Returns a list of objects with requested type
-    """
+def _is_dataset(node: Dict):
+    return node.get('module') == _nexus_dataset
+
+
+def _is_link(node: Dict):
+    return node.get('module') == _nexus_link
 
-    def _visit_nodes_for_type(
-        obj: Dict, requested_type: str, objects_found: List[H5Group]
-    ):
-        try:
-            for child in obj[_nexus_children]:
-                if child["type"] == requested_type:
-                    objects_found.append(
-                        _Node(
-                            group=child,
-                            parent=obj,
-                            name="",
-                            file={_nexus_children: [obj]},
-                        )
-                    )
-                _visit_nodes_for_type(child, requested_type, objects_found)
-        except KeyError:
-            # If this object does not have "children" array then go to next
-            pass
 
-    objects_with_requested_type: List[H5Group] = []
-    _visit_nodes_for_type(root, type_name, objects_with_requested_type)
+def _is_stream(node: Dict):
+    return 'module' in node and not (_is_dataset(node) or _is_link(node))
 
-    return objects_with_requested_type
+
+def contains_stream(group: JSONGroup) -> bool:
+    """Return True if the group contains a stream object"""
+    return (
+        isinstance(group, JSONGroup)
+        and _nexus_children in group._node
+        and any(map(_is_stream, group._node[_nexus_children]))
+    )
 
 
 class JSONTypeStringID:
@@ -274,10 +218,11 @@ class JSONNode:
         self._file = parent.file if parent is not None else self
         self._parent = self if parent is None else parent
         self._node = node
+        name = _name(self._node)
         if parent is None or parent.name == '/':
-            self._name = f'/{self._node.get(_nexus_name, "")}'
+            self._name = f'/{name}'
         else:
-            self._name = f'{parent.name}/{self._node[_nexus_name]}'
+            self._name = f'{parent.name}/{name}'
 
     @property
     def attrs(self) -> JSONAttributeManager:
@@ -300,9 +245,14 @@ class JSONDataset(JSONNode):
     @property
     def dtype(self) -> str:
         try:
-            dtype = self._node[_nexus_dataset]["type"]
+            dtype = self._node[_nexus_config]["type"]
         except KeyError:
-            dtype = self._node[_nexus_dataset]["dtype"]
+            if "dtype" not in self._node[_nexus_config] and isinstance(
+                self._node[_nexus_config][_nexus_values], str
+            ):
+                dtype = 'string'
+            else:
+                dtype = self._node[_nexus_config]["dtype"]
         if dtype == 'string':
             return np.dtype(str)
         return np.dtype(dtype)
@@ -313,10 +263,10 @@ class JSONDataset(JSONNode):
 
     @property
     def shape(self):
-        return np.asarray(self._node[_nexus_values]).shape
+        return np.asarray(self._node[_nexus_config][_nexus_values]).shape
 
     def __getitem__(self, index):
-        return np.asarray(self._node[_nexus_values])[index]
+        return np.asarray(self._node[_nexus_config][_nexus_values])[index]
 
     def read_direct(self, buf, source_sel):
         buf[...] = self[source_sel]
@@ -337,16 +287,15 @@ class JSONGroup(JSONNode):
         if contains_stream(self):
             return []
         children = self._node[_nexus_children]
-        return [child[_nexus_name] for child in children if not contains_stream(child)]
+        return [_name(child) for child in children if not contains_stream(child)]
 
     def items(self) -> List[Tuple[str, JSONNode]]:
         return [(key, self[key]) for key in self.keys()]
 
     def _as_group_or_dataset(self, item, parent):
-        if item['type'] == _nexus_group:
+        if _is_group(item):
             return JSONGroup(item, parent=parent)
-        else:
-            return JSONDataset(item, parent=parent)
+        return JSONDataset(item, parent=parent)
 
     def __getitem__(self, name: str) -> Union[JSONDataset, JSONGroup]:
         if name.startswith('/') and name.count('/') == 1:
@@ -357,11 +306,11 @@ class JSONGroup(JSONNode):
             parent = self
 
         for child in parent._node[_nexus_children]:
-            if child.get(_nexus_name) != name.split('/')[-1]:
+            if _name(child) != name.split('/')[-1]:
                 continue
-            if child.get('type') == _nexus_link:
-                return self[child["target"]]
-            if child.get('type') in (_nexus_dataset, _nexus_group):
+            if _is_link(child):
+                return self[child[_nexus_config]["target"]]
+            if _is_group(child) or _is_dataset(child):
                 return self._as_group_or_dataset(child, parent)
 
         raise KeyError(f"Unable to open object (object '{name}' doesn't exist)")
@@ -371,12 +320,10 @@ class JSONGroup(JSONNode):
 
     def visititems(self, callable):
         def skip(node):
-            return node['type'] == _nexus_link or contains_stream(self)
+            return _is_link(node) or contains_stream(self)
 
         children = [
-            child[_nexus_name]
-            for child in self._node[_nexus_children]
-            if not skip(child)
+            _name(child) for child in self._node[_nexus_children] if not skip(child)
         ]
         for key in children:
             item = self[key]
@@ -409,28 +356,30 @@ class StreamInfo:
 
 
 def get_streams_info(root: Dict) -> List[StreamInfo]:
-    found_streams = _find_by_type(_nexus_stream, root)
+    found_streams = [node for node in _visitnodes(root) if _is_stream(node)]
     streams = []
     for stream in found_streams:
         try:
-            dtype = _filewriter_to_supported_numpy_dtype[stream["stream"]["dtype"]]
+            dtype = _filewriter_to_supported_numpy_dtype[stream[_nexus_config]["dtype"]]
         except KeyError:
             try:
-                dtype = _filewriter_to_supported_numpy_dtype[stream["stream"]["type"]]
+                dtype = _filewriter_to_supported_numpy_dtype[
+                    stream[_nexus_config]["type"]
+                ]
             except KeyError:
                 dtype = None
 
         units = "dimensionless"
         try:
-            units = _get_attribute_value(stream.parent, _nexus_units)
+            units = _get_attribute_value(stream, _nexus_units)
         except MissingAttribute:
             pass
 
         streams.append(
             StreamInfo(
-                stream["stream"]["topic"],
-                stream["stream"]["writer_module"],
-                stream["stream"]["source"],
+                stream[_nexus_config]["topic"],
+                stream["module"],
+                stream[_nexus_config]["source"],
                 dtype,
                 units,
             )


Test patch:
diff --git a/tests/io/json_nexus_examples/array_dataset.json b/tests/io/json_nexus_examples/array_dataset.json
new file mode 100644
index 00000000..82f0e4fa
--- /dev/null
+++ b/tests/io/json_nexus_examples/array_dataset.json
@@ -0,0 +1,20 @@
+{
+  "module": "dataset",
+  "config": {
+    "name": "slit_edges",
+    "values": [
+      0.0,
+      15.0,
+      180.0,
+      195.0
+    ],
+    "type": "double"
+  },
+  "attributes": [
+    {
+      "name": "units",
+      "dtype": "string",
+      "values": "deg"
+    }
+  ]
+}
diff --git a/tests/io/json_nexus_examples/dataset.json b/tests/io/json_nexus_examples/dataset.json
new file mode 100644
index 00000000..d58d7147
--- /dev/null
+++ b/tests/io/json_nexus_examples/dataset.json
@@ -0,0 +1,8 @@
+{
+  "module": "dataset",
+  "config": {
+    "name": "name",
+    "values": "YMIR",
+    "type": "string"
+  }
+}
diff --git a/tests/io/json_nexus_examples/detector.json b/tests/io/json_nexus_examples/detector.json
index e5d8d5cf..a5911a70 100644
--- a/tests/io/json_nexus_examples/detector.json
+++ b/tests/io/json_nexus_examples/detector.json
@@ -3,15 +3,15 @@
   "name": "detector_0",
   "children": [
     {
-      "type": "dataset",
-      "name": "detector_number",
-      "values": [
-        1,
-        2,
-        3,
-        4
-      ],
-      "dataset": {
+      "module": "dataset",
+      "config": {
+        "name": "detector_number",
+        "values": [
+          1,
+          2,
+          3,
+          4
+        ],
         "size": [
           4
         ],
diff --git a/tests/io/json_nexus_examples/entry.json b/tests/io/json_nexus_examples/entry.json
index 200e4355..60dbd1df 100644
--- a/tests/io/json_nexus_examples/entry.json
+++ b/tests/io/json_nexus_examples/entry.json
@@ -3,14 +3,13 @@
   "name": "entry",
   "children": [
     {
-      "type": "dataset",
-      "name": "title",
-      "values": "my experiment",
-      "dataset": {
+      "module": "dataset",
+      "config": {
+        "name": "title",
+        "values": "my experiment",
         "string_size": 13,
         "type": "string"
-      },
-      "attributes": []
+      }
     }
   ],
   "attributes": [
diff --git a/tests/io/json_nexus_examples/event_data.json b/tests/io/json_nexus_examples/event_data.json
index 59d3a8cb..be4787eb 100644
--- a/tests/io/json_nexus_examples/event_data.json
+++ b/tests/io/json_nexus_examples/event_data.json
@@ -3,16 +3,16 @@
   "name": "events_0",
   "children": [
     {
-      "type": "dataset",
-      "name": "event_id",
-      "values": [
-        1,
-        2,
-        3,
-        1,
-        3
-      ],
-      "dataset": {
+      "module": "dataset",
+      "config": {
+        "name": "event_id",
+        "values": [
+          1,
+          2,
+          3,
+          1,
+          3
+        ],
         "size": [
           5
         ],
@@ -21,16 +21,16 @@
       "attributes": []
     },
     {
-      "type": "dataset",
-      "name": "event_time_offset",
-      "values": [
-        456,
-        743,
-        347,
-        345,
-        632
-      ],
-      "dataset": {
+      "module": "dataset",
+      "config": {
+        "name": "event_time_offset",
+        "values": [
+          456,
+          743,
+          347,
+          345,
+          632
+        ],
         "size": [
           5
         ],
@@ -46,15 +46,15 @@
       ]
     },
     {
-      "type": "dataset",
-      "name": "event_time_zero",
-      "values": [
-        360917979000000000,
-        360917980000000000,
-        360917981000000000,
-        360917982000000000
-      ],
-      "dataset": {
+      "module": "dataset",
+      "config": {
+        "name": "event_time_zero",
+        "values": [
+          360917979000000000,
+          360917980000000000,
+          360917981000000000,
+          360917982000000000
+        ],
         "size": [
           4
         ],
@@ -76,15 +76,15 @@
       ]
     },
     {
-      "type": "dataset",
-      "name": "event_index",
-      "values": [
-        0,
-        3,
-        3,
-        5
-      ],
-      "dataset": {
+      "module": "dataset",
+      "config": {
+       "name": "event_index",
+       "values": [
+         0,
+         3,
+         3,
+         5
+       ],
         "size": [
           4
         ],
diff --git a/tests/io/json_nexus_examples/instrument.json b/tests/io/json_nexus_examples/instrument.json
new file mode 100644
index 00000000..f89f86e9
--- /dev/null
+++ b/tests/io/json_nexus_examples/instrument.json
@@ -0,0 +1,1303 @@
+{
+  "type": "group",
+  "name": "entry",
+  "children": [
+    {
+      "module": "dataset",
+      "config": {
+        "name": "title",
+        "values": "my experiment",
+        "string_size": 13,
+        "type": "string"
+      }
+    },
+    {
+      "name": "instrument",
+      "type": "group",
+      "attributes": [
+        {
+          "name": "NX_class",
+          "dtype": "string",
+          "values": "NXinstrument"
+        }
+      ],
+      "children": [
+        {
+          "module": "dataset",
+          "config": {
+            "name": "name",
+            "values": "YMIR",
+            "type": "string"
+          }
+        },
+        {
+          "name": "light_source",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXsource"
+            }
+          ],
+          "children": [
+            {
+              "module": "dataset",
+              "config": {
+                "name": "probe",
+                "values": "visible light",
+                "type": "string"
+              }
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/light_source/transformations/translation"
+              }
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation",
+                    "values": -2.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "mini_chopper",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXdisk_chopper"
+            }
+          ],
+          "children": [
+            {
+              "name": "delay",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "delay_source_chopper",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "slits",
+                "values": 2,
+                "type": "int64"
+              }
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "slit_height",
+                "values": 0.05,
+                "type": "double"
+              },
+              "attributes": [
+                {
+                  "name": "units",
+                  "dtype": "string",
+                  "values": "m"
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "radius",
+                "values": 0.15,
+                "type": "double"
+              },
+              "attributes": [
+                {
+                  "name": "units",
+                  "dtype": "string",
+                  "values": "m"
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "slit_edges",
+                "values": [
+                  0.0,
+                  15.0,
+                  180.0,
+                  195.0
+                ],
+                "type": "double"
+              },
+              "attributes": [
+                {
+                  "name": "units",
+                  "dtype": "string",
+                  "values": "deg"
+                }
+              ]
+            },
+            {
+              "module": "tdct",
+              "config": {
+                "source": "chopper_source",
+                "topic": "ymir_motion"
+              }
+            },
+            {
+              "name": "rotation_speed",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-ChpSy1:Chop-MIC-101:Spd_SP",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "1/s"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "1/s"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/mini_chopper/transformations/rotation"
+              }
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "rotation",
+                    "values": 90.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "rotation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "degrees"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        1.0,
+                        0.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/mini_chopper/transformations/translation",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation",
+                    "values": 4.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/mini_chopper/transformations/translation1",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation1",
+                    "values": -1.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        1.0,
+                        0.0,
+                        0.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "laser_monitor",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXmonitor"
+            }
+          ],
+          "children": [
+            {
+              "name": "edge_events",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "tdct",
+                  "config": {
+                    "source": "YMIR-TS:Ctrl-EVR-01:01-TS-I",
+                    "topic": "ymir_motion"
+                  }
+                }
+              ]
+            },
+            {
+              "name": "laser_fast_data",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "se00",
+                  "config": {
+                    "source": "YMIR-SETS:SE-BADC-001:VALUE",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/laser_monitor/transformations/translation"
+              }
+            },
+            {
+              "name": "laser_slow_data",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SETS:SE-BADC-001:SLOWDATA",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "name": "laser_ptp_status",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SETS:SE-BPTP-001:PTP_STATUS",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation",
+                    "values": 4.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        1.0,
+                        0.0,
+                        0.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_monitor/transformations/translation1",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation1",
+                    "values": 4.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "laser_source",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXsource"
+            }
+          ],
+          "children": [
+            {
+              "module": "dataset",
+              "config": {
+                "name": "probe",
+                "values": "visible_light",
+                "type": "string"
+              }
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/laser_source/transformations/rotation"
+              }
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "rotation",
+                    "values": 90.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "rotation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "degrees"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        1.0,
+                        0.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_source/transformations/translation",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation",
+                    "values": 4.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_source/transformations/translation1",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation1",
+                    "values": -2.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        1.0,
+                        0.0,
+                        0.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "screen",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXbeam_stop"
+            }
+          ],
+          "children": [
+            {
+              "name": "geometry",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXgeometry"
+                }
+              ],
+              "children": [
+                {
+                  "name": "shape",
+                  "type": "group",
+                  "attributes": [
+                    {
+                      "name": "NX_class",
+                      "dtype": "string",
+                      "values": "NXshape"
+                    }
+                  ],
+                  "children": [
+                    {
+                      "module": "dataset",
+                      "config": {
+                        "name": "size",
+                        "values": [
+                          0.01,
+                          0.6,
+                          0.4
+                        ],
+                        "type": "double"
+                      },
+                      "attributes": [
+                        {
+                          "name": "units",
+                          "dtype": "string",
+                          "values": "m"
+                        }
+                      ]
+                    },
+                    {
+                      "module": "dataset",
+                      "config": {
+                        "name": "shape",
+                        "values": "nxbox",
+                        "type": "string"
+                      }
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/screen/transformations/translation"
+              }
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation",
+                    "values": 0.3,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "laser_aperature",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXaperture"
+            }
+          ],
+          "children": [
+            {
+              "name": "ioc_timestamps_z",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-X-01:Mtr.RBV",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "mm"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "ioc_timestamps_x",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-Y-01:Mtr.RBV",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "mm"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "ioc_timestamps_y",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-Z-01:Mtr.RBV",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "mm"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "motor_speed_x",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-Y-01:Mtr.VELO",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "name": "motor_speed_y",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-Z-01:Mtr.VELO",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "name": "motor_speed_z",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SpScn:MC-X-01:Mtr.VELO",
+                    "topic": "ymir_motion",
+                    "dtype": "double"
+                  }
+                }
+              ]
+            },
+            {
+              "module": "dataset",
+              "config": {
+                "name": "depends_on",
+                "values": "/entry/instrument/laser_aperature/transformations/x_translation"
+              }
+            },
+            {
+              "type": "group",
+              "name": "transformations",
+              "children": [
+                {
+                  "name": "x_translation",
+                  "type": "group",
+                  "attributes": [
+                    {
+                      "name": "NX_class",
+                      "dtype": "string",
+                      "values": "NXlog"
+                    },
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        1.0,
+                        0.0,
+                        0.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_aperature/transformations/y_translation",
+                      "dtype": "string"
+                    }
+                  ],
+                  "children": [
+                    {
+                      "module": "f144",
+                      "config": {
+                        "source": "YMIR-SpScn:MC-Y-01:Mtr-RBV-TSE",
+                        "topic": "ymir_motion",
+                        "dtype": "double"
+                      }
+                    }
+                  ]
+                },
+                {
+                  "name": "y_translation",
+                  "type": "group",
+                  "attributes": [
+                    {
+                      "name": "NX_class",
+                      "dtype": "string",
+                      "values": "NXlog"
+                    },
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        1.0,
+                        0.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_aperature/transformations/z_translation",
+                      "dtype": "string"
+                    }
+                  ],
+                  "children": [
+                    {
+                      "module": "f144",
+                      "config": {
+                        "source": "YMIR-SpScn:MC-Z-01:Mtr-RBV-TSE",
+                        "topic": "ymir_motion",
+                        "dtype": "double"
+                      }
+                    }
+                  ]
+                },
+                {
+                  "name": "z_translation",
+                  "type": "group",
+                  "attributes": [
+                    {
+                      "name": "NX_class",
+                      "dtype": "string",
+                      "values": "NXlog"
+                    },
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "mm"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_aperature/transformations/translation2",
+                      "dtype": "string"
+                    }
+                  ],
+                  "children": [
+                    {
+                      "module": "f144",
+                      "config": {
+                        "source": "YMIR-SpScn:MC-X-01:Mtr-RBV-TSE",
+                        "topic": "ymir_motion",
+                        "dtype": "double"
+                      }
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation2",
+                    "values": 4.0,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        0.0,
+                        0.0,
+                        1.0
+                      ]
+                    },
+                    {
+                      "name": "depends_on",
+                      "values": "/entry/instrument/laser_aperature/transformations/translation1",
+                      "dtype": "string"
+                    }
+                  ]
+                },
+                {
+                  "module": "dataset",
+                  "config": {
+                    "name": "translation1",
+                    "values": 1.5,
+                    "type": "double"
+                  },
+                  "attributes": [
+                    {
+                      "name": "transformation_type",
+                      "dtype": "string",
+                      "values": "translation"
+                    },
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "m"
+                    },
+                    {
+                      "name": "vector",
+                      "dtype": "float",
+                      "values": [
+                        1.0,
+                        0.0,
+                        0.0
+                      ]
+                    }
+                  ]
+                }
+              ],
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "values": "NXtransformations"
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "name": "lakeshore",
+          "type": "group",
+          "attributes": [
+            {
+              "name": "NX_class",
+              "dtype": "string",
+              "values": "NXsensor"
+            }
+          ],
+          "children": [
+            {
+              "module": "dataset",
+              "config": {
+                "name": "measurement",
+                "values": "temperature",
+                "type": "string"
+              }
+            },
+            {
+              "name": "temperatur_sensor_1",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SEE:SE-LS336-004:KRDG0",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "K"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "K"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "temperature_sensor_2",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SEE:SE-LS336-004:KRDG1",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "K"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "K"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "setpoint_ch_1",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SEE:SE-LS336-004:SETP_S1",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "K"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "K"
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "name": "setpoint_ch_2",
+              "type": "group",
+              "attributes": [
+                {
+                  "name": "NX_class",
+                  "dtype": "string",
+                  "values": "NXlog"
+                }
+              ],
+              "children": [
+                {
+                  "module": "f144",
+                  "config": {
+                    "source": "YMIR-SEE:SE-LS336-004:SETP_S2",
+                    "topic": "ymir_motion",
+                    "dtype": "double",
+                    "value_units": "K"
+                  },
+                  "attributes": [
+                    {
+                      "name": "units",
+                      "dtype": "string",
+                      "values": "K"
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "attributes": [
+    {
+      "string_size": 7,
+      "type": "string",
+      "name": "NX_class",
+      "values": "NXentry"
+    }
+  ]
+}
diff --git a/tests/io/json_nexus_examples/log.json b/tests/io/json_nexus_examples/log.json
index b4262bbd..34c4d627 100644
--- a/tests/io/json_nexus_examples/log.json
+++ b/tests/io/json_nexus_examples/log.json
@@ -3,16 +3,13 @@
   "name": "test_log",
   "children": [
     {
-      "type": "dataset",
-      "name": "value",
-      "values": [
-        1.1,
-        2.2,
-        3.3
-      ],
-      "dataset": {
-        "size": [
-          3
+      "module": "dataset",
+      "config": {
+        "name": "value",
+        "values": [
+          1.1,
+          2.2,
+          3.3
         ],
         "type": "float64"
       },
@@ -26,16 +23,13 @@
       ]
     },
     {
-      "type": "dataset",
-      "name": "time",
-      "values": [
-        13,
-        24,
-        35
-      ],
-      "dataset": {
-        "size": [
-          3
+      "module": "dataset",
+      "config": {
+        "name": "time",
+        "values": [
+          13,
+          24,
+          35
         ],
         "type": "float64"
       },
diff --git a/tests/io/load_nexus_json_test.py b/tests/io/load_nexus_json_test.py
index 3fe0c0a4..fda1ef61 100644
--- a/tests/io/load_nexus_json_test.py
+++ b/tests/io/load_nexus_json_test.py
@@ -180,7 +180,7 @@ def test_nexus_json_load_log(examples):
 
 def test_nexus_json_load_log_utf8_unit(examples):
     log = examples.log
-    assert log['children'][0]['name'] == 'value', 'is the expected child'
+    assert log['children'][0]['config']['name'] == 'value', 'is the expected child'
     assert log['children'][0]['attributes'][0]['name'] == 'units'
     log['children'][0]['attributes'][0]['values'] = '\u00b0'  # '°', i.e., degrees
 
@@ -200,3 +200,25 @@ def test_nexus_json_load_log_utf8_unit(examples):
         },
     )
     sc.testing.assert_identical(loaded, expected)
+
+
+# TODO: remove warning filter
+# Loading a NXmonitor fails with
+# 'Signal is not array like' error and issues a warning.
+# But this should probably be fixed elsewhere.
+@pytest.mark.filterwarnings('ignore::UserWarning')
+def test_nexus_json_load_ymir_instrument(examples):
+    make_group(examples.instrument)[()]
+
+
+def test_nexus_json_load_dataset(examples):
+    dg = make_group(examples.dataset)[()]
+    assert dg['name'] == 'YMIR'
+
+
+def test_nexus_json_load_array_dataset(examples):
+    dg = make_group(examples.array_dataset)[()]
+    sc.testing.assert_identical(
+        dg['slit_edges'],
+        sc.array(dims=['dim_0'], values=[0.0, 15.0, 180.0, 195.0], unit='deg'),
+    )
diff --git a/tests/io/nexus_helpers.py b/tests/io/nexus_helpers.py
index eb2e2b62..62dd3aff 100644
--- a/tests/io/nexus_helpers.py
+++ b/tests/io/nexus_helpers.py
@@ -13,6 +13,7 @@ import scipp as sc
 
 from scippneutron.io.nexus._json_nexus import (
     JSONGroup,
+    _name,
     make_json_attr,
     make_json_dataset,
 )
@@ -239,7 +240,7 @@ class InMemoryNeXusWriter:
 def _get_child(obj, name):
     children = obj["children"]
     for child in children:
-        if child.get('name') == name:
+        if _name(child) == name:
             return child
     return None
 
@@ -259,7 +260,7 @@ def _add_link_to_json(file_root: Dict, new_path: str, target_path: str):
     link_name = new_path_split[-1]
     parent_path = "/".join(new_path_split[:-1])
     parent_group = _get_object_by_path(file_root, parent_path)
-    link = {"type": "link", "name": link_name, "target": target_path}
+    link = {"module": "link", "config": {"name": link_name, "target": target_path}}
     existing_object = _get_object_by_path(parent_group, link_name)
     if existing_object is not None:
         parent_group["children"].remove(existing_object)
@@ -314,11 +315,10 @@ class JsonWriter:
 
     def add_stream(self, file_root: Dict, stream: Stream):
         new_stream = {
-            "type": "stream",
-            "stream": {
+            "module": stream.writer_module,
+            "config": {
                 "topic": stream.topic,
                 "source": stream.source,
-                "writer_module": stream.writer_module,
                 "type": stream.type,
                 "value_units": stream.value_units,
             },