Repository: pydap/pydap

Issue:
escape white space in variable/group names when creating a dataset
<!-- Thank you very much for your input! -->

### Description

Without escaping the variable name, pydap creates an incorrect dataset. Consider the following example dmr

```python
<Dataset name="FamilyNames.h5">
    <Group name="Last Name">
        <String name="Simpson"/>
    </Group>
    <Group name="First Names">
        <String name="Homer J."/>
        <String name="Bart"/>
        <String name="Lisa"/>
        <String name="Maggie"/>
    </Group>
</Dataset>
```

Trying to open this dataset results in the following error:

```
AttributeError: '<class 'pydap.model.GroupType'>' object has no attribute 'path'
```

The problem, however, is that when there is a space in the name of a group, pydap automatically creates a nested Group. For example with following fqn: ```/First Name/Lisa```, pydap initially (correctly) creates the Group `Last Name`, but later it also creates two additional Groups: `"First"` and `"Name"`, when creating the variable `Lisa`. `Lisa` is created within the Group `Name`. All this is avoided when escaping the Group name. A similar problem occurs with the variable name (non-fqn) `"Homer J."`. 

The issue is not the `"."`. The issue is the empty white space.

Already got a fix!


Discussion:

Patch:
diff --git a/src/pydap/parsers/dmr.py b/src/pydap/parsers/dmr.py
index dc8a336..2194408 100644
--- a/src/pydap/parsers/dmr.py
+++ b/src/pydap/parsers/dmr.py
@@ -42,22 +42,20 @@ def dap4_to_numpy_typemap(type_string):
 
 def get_variables(node, prefix="") -> dict:
     variables = collections.OrderedDict()
-    group_name = node.get("name")
+    group_name = [
+        pydap.lib._quote(node.get("name")) if node.get("name") is not None else None
+    ][0]
     if group_name is None:
         return variables
     if node.tag != "Dataset":
         prefix = prefix + "/" + group_name
     for subnode in node:
-        if subnode.tag in dmr_atomic_types:
+        if subnode.tag in dmr_atomic_types + ("String",):
             name = subnode.get("name")
             if prefix != "":
                 name = prefix + "/" + name
             variables[name] = {"element": subnode, "parent": node.tag}
         variables.update(get_variables(subnode, prefix))
-    strings = node.findall("String")
-    for string in strings:
-        name = string.get("name")
-        variables[name] = {"element": string, "parent": node.tag}
     return variables
 
 
@@ -299,7 +297,7 @@ def dmr_to_dataset(dmr):
                 Dims.append(dim)
         # pass along maps
         var_kwargs = {
-            "name": name,
+            "name": pydap.lib._quote(name),
             "data": data,
             "dimensions": Dims,
             "attributes": variable["attributes"],
@@ -367,7 +365,10 @@ class DMRParser(object):
             Maps = Groups[key].pop("Maps", None)
             attributes = Groups[key].pop("attributes", None)
             dataset.createGroup(
-                name=key, dimensions=dims, Maps=Maps, attributes=attributes
+                name=pydap.lib._quote(key),
+                dimensions=dims,
+                Maps=Maps,
+                attributes=attributes,
             )
 
         return dataset


Test patch:
diff --git a/src/pydap/tests/test_parsers_dmr.py b/src/pydap/tests/test_parsers_dmr.py
index b303ec5..070c18c 100644
--- a/src/pydap/tests/test_parsers_dmr.py
+++ b/src/pydap/tests/test_parsers_dmr.py
@@ -309,3 +309,27 @@ class TestAttrsTypesDMRParser(unittest.TestCase):
         </Dataset>"""
         ds = dmr_to_dataset(dmr)
         assert ds["bears"].attributes["attr"] == 100.0
+
+    def test_escapedcharacters(self):
+        dmr = """
+        <Dataset name="FamilyNames.h5">\n
+            <Group name="Last Names">\n
+                <String name="Simpson"/>\n
+            </Group>\n
+            <Group name="First Names">\n
+                <String name="Homer J."/>\n
+                <String name="Bart"/>\n
+                <String name="Lisa"/>\n
+                <String name="Maggie"/>\n
+            </Group>\n
+            <Group name="Ages">\n
+                <String name="35.0"/>\n
+                <String name="8.5"/>\n
+                <String name="7.1"/>\n
+                <String name="2.1"/>\n
+            </Group>\n
+            <Attribute name='description' type='String' value='hello'/>\n
+        </Dataset>
+        """
+        ds = dmr_to_dataset(dmr)
+        assert ds["Last Names"].name == "Last%20Names"