dap4/d4core/src/main/java/dap4/core/dmr/DapDataset.java
public DapNode
    lookup(String fqn, DapSort... sortset)
            throws DapException
    {
        fqn = fqn.trim();
        if(fqn == null)
            return null;
        if("".equals(fqn) || "/".equals(fqn)) {
            return this;
        }
        if(fqn.charAt(0) == '/')
            fqn = fqn.substring(1); // remove leading /
        //Check first for an atomic type
        TypeSort ts = TypeSort.getTypeSort(fqn);
        if(ts != null && ts.isAtomic()) {
            // see if we are looking for an atomic type
            for(DapSort ds: sortset) {
                if(ds == DapSort.ATOMICTYPE)
                    return DapType.lookup(ts);
            }
        }

        // Do not use split to be able to look for escaped '/'
        // Warning: elements of path are unescaped
        List<String> path = DapUtil.backslashSplit(fqn, '/');
        DapGroup current = dataset;
        // Walk all but the last element to walk group path
        for(int i = 0; i < path.size() - 1; i++) {
            String groupname = Escape.backslashUnescape(path.get(i));
            DapGroup g = (DapGroup)current.findInGroup(groupname, DapSort.GROUP);
            if(g == null)
                return null;
            assert (g.getSort() == DapSort.GROUP);
            current = (DapGroup) g;
        }
        if(!ALLOWFIELDMAPS) {
            String targetname = Escape.backslashUnescape(path.get(path.size()-1));
            return current.findInGroup(targetname, sortset);
        } else { // ALLOWFIELDMAPS)
            // We need to handle the last segment of the group path
            // to deal with struct walking using '.'. We need to obtain the last segment
            // with escapes intact so we can spot '.' separators.
            // Locate the last element in the last group
            // Start by looking for any containing structure
            String varpart = path.get(path.size() - 1); // Note that this still has escapes
            // So that '.' parsing will be correct.
            List<String> structpath = DapUtil.backslashSplit(varpart, '.');
            String outer = Escape.backslashUnescape(structpath.get(0));
            if(structpath.size() == 1) {
                return current.findInGroup(outer, sortset);
            } else {// It is apparently a structure field
                // locate the outermost structure to start with
                DapStructure currentstruct = (DapStructure) current.findInGroup(outer, DapSort.STRUCTURE, DapSort.SEQUENCE);
                if(currentstruct == null)
                    return null; // does not exist
                // search for the innermost structure
                String fieldname;
                for(int i = 1; i < structpath.size() - 1; i++) {
                    fieldname = Escape.backslashUnescape(structpath.get(i));
                    DapVariable field = (DapVariable) currentstruct.findByName(fieldname);
                    if(field == null)
                        throw new DapException("No such field: " + fieldname);
                    if(!field.isCompound())
                        break;
                    currentstruct = (DapStructure) field.getBaseType();
                }
                fieldname = Escape.backslashUnescape(structpath.get(structpath.size() - 1));
                DapVariable field = currentstruct.findByName(fieldname);
                if(field == null)
                    throw new DapException("No such field: " + fieldname);
                if(field.getSort().oneof(sortset))
                    return (field);
            }
        }
        return null;
    }
public DapNode
    lookup(String fqn, DapSort... sortset)
            throws DapException
    {
        fqn = fqn.trim();
        if(fqn == null)
            return null;
        if("".equals(fqn) || "/".equals(fqn)) {
            return this;
        }
        if(fqn.charAt(0) == '/')
            fqn = fqn.substring(1); // remove leading /
        //Check first for an atomic type
        TypeSort ts = TypeSort.getTypeSort(fqn);
        if(ts != null && ts.isAtomic()) {
            // see if we are looking for an atomic type
            for(DapSort ds: sortset) {
                if(ds == DapSort.ATOMICTYPE)
                    return DapType.lookup(ts);
            }
        }

        // Do not use split to be able to look for escaped '/'
        // Warning: elements of path are unescaped
        List<String> path = DapUtil.backslashSplit(fqn, '/');
        DapGroup current = dataset;
        // Walk all but the last element to walk group path
        for(int i = 0; i < path.size() - 1; i++) {
            String groupname = Escape.backslashUnescape(path.get(i));
            DapGroup g = (DapGroup)current.findInGroup(groupname, DapSort.GROUP);
            if(g == null)
                return null;
            assert (g.getSort() == DapSort.GROUP);
            current = (DapGroup) g;
        }
        if(!ALLOWFIELDMAPS) {
            String targetname = Escape.backslashUnescape(path.get(path.size()-1));
            return current.findInGroup(targetname, sortset);
        } else { // ALLOWFIELDMAPS)
            // We need to handle the last segment of the group path
            // to deal with struct walking using '.'. We need to obtain the last segment
            // with escapes intact so we can spot '.' separators.
            // Locate the last element in the last group
            // Start by looking for any containing structure
            String varpart = path.get(path.size() - 1); // Note that this still has escapes
            // So that '.' parsing will be correct.
            List<String> structpath = DapUtil.backslashSplit(varpart, '.');
            String outer = Escape.backslashUnescape(structpath.get(0));
            if(structpath.size() == 1) {
                return current.findInGroup(outer, sortset);
            } else {// It is apparently a structure field
                // locate the outermost structure to start with
                DapStructure currentstruct = (DapStructure) current.findInGroup(outer, DapSort.STRUCTURE, DapSort.SEQUENCE);
                if(currentstruct == null)
                    return null; // does not exist
                // search for the innermost structure
                String fieldname;
                for(int i = 1; i < structpath.size() - 1; i++) {
                    fieldname = Escape.backslashUnescape(structpath.get(i));
                    DapVariable field = (DapVariable) currentstruct.findByName(fieldname);
                    if(field == null)
                        throw new DapException("No such field: " + fieldname);
                    if(!field.isCompound())
                        break;
                    currentstruct = (DapStructure) field.getBaseType();
                }
                fieldname = Escape.backslashUnescape(structpath.get(structpath.size() - 1));
                DapVariable field = currentstruct.findByName(fieldname);
                if(field == null)
                    throw new DapException("No such field: " + fieldname);
                if(field.getSort().oneof(sortset))
                    return (field);
            }
        }
        return null;
    }
Parse an FQN and use it to trace to a specific
object in a dataset. Note that this is quite
tricky in the face of backslash escapes.
Because of backslash escapes, we cannot
use the String.split function because it does appear to be
possible to write a regexp that handles preceding backslashes
correctly. Instead, we must parse character by character left to right.
Traversal into structs:
In theory, a map variable could point to a field of a structure.
However, in practice, this will not work because we would need a
specific instance of that field, which means including dimension
indices must be included starting from some top-level variable.
We choose, for now, to make that illegal until such time as there
is a well-defined meaning for this.
Note: this assumes the fqn is absolute (i.e. starts with '/').

@param fqn     the fully qualified name
@param sortset the kind(s) of object we are looking for
@return the matching Dap Node or null if not found