dap4/d4lib/src/main/java/dap4/dap4lib/DMRPrinter.java
public void
    printNode(DapNode node)
            throws IOException
    {
        if(node == null)
            return;

        DapSort sort = node.getSort();
        String dmrname = sort.getName();

        switch (sort) {
        case DATASET:// treat like group
        case GROUP:
            if(!this.ce.references(node)) break;
            DapGroup group = (DapGroup) node;
            printer.marginPrint("<" + dmrname);
            int flags = (sort == DapSort.DATASET ? PERLINE : NILFLAGS);
            printXMLAttributes(node, ce, flags);
            printer.println(">");
            printer.indent();
            // Make the output order conform to the spec
            if(group.getDimensions().size() > 0) {
                for(DapNode subnode : group.getDimensions()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            }
            if(group.getEnums().size() > 0) {
                for(DapNode subnode : group.getEnums()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            }
            if(group.getVariables().size() > 0)
                for(DapNode subnode : group.getVariables()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            printMetadata(node);
            if(group.getGroups().size() > 0)
                for(DapNode subnode : group.getGroups()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            printer.outdent();
            printer.marginPrint("</" + dmrname + ">");
            break;

        case DIMENSION:
            if(!this.ce.references(node)) break;
            DapDimension dim = (DapDimension) node;
            if(!dim.isShared()) break; // ignore, here, anonymous dimensions
            printer.marginPrint("<" + dmrname);
            printXMLAttributes(node, ce, NILFLAGS);
            if(dim.isUnlimited())
                printXMLAttribute(AbstractDSP.UCARTAGUNLIMITED, "1", NILFLAGS);
            if(hasMetadata(node)) {
                printer.println(">");
                printMetadata(node);
                printer.marginPrint("</" + dmrname + ">");
            } else {
                printer.print("/>");
            }
            break;

        case ENUMERATION:
            if(!this.ce.references(node)) break;
            DapEnumeration en = (DapEnumeration) node;
            printer.marginPrint("<" + dmrname);
            printXMLAttributes(en, ce, NILFLAGS);
            printer.println(">");
            printer.indent();
            List<String> econstnames = en.getNames();
            for(String econst : econstnames) {
                DapEnumConst value = en.lookup(econst);
                assert (value != null);
                printer.marginPrintln(
                        String.format("<EnumConst name=\"%s\" value=\"%d\"/>",
                                Escape.entityEscape(econst, null), value.getValue()));
            }
            printMetadata(node);
            printer.outdent();
            printer.marginPrint("</" + dmrname + ">");
            break;

        case VARIABLE:
            if(!this.ce.references(node)) break;
            DapVariable var = (DapVariable) node;
            DapType type = var.getBaseType();
            printer.marginPrint("<" + type.getTypeSort().name());
            printXMLAttributes(node, ce, NILFLAGS);
            if(type.isAtomic()) {
                if((hasMetadata(node) || hasDimensions(var) || hasMaps(var))) {
                    printer.println(">");
                    printer.indent();
                    if(hasDimensions(var))
                        printDimrefs(var);
                    if(hasMetadata(var))
                        printMetadata(var);
                    if(hasMaps(var))
                        printMaps(var);
                    printer.outdent();
                    printer.marginPrint("</" + type.getTypeSort().name() + ">");
                } else
                    printer.print("/>");
            } else if(type.getTypeSort().isCompound()) {
                DapStructure struct = (DapStructure) type;
                printer.println(">");
                printer.indent();
                for(DapVariable field : struct.getFields()) {
                    if(!this.ce.references(field)) continue;
                    printNode(field);
                    printer.eol();
                }
                printDimrefs(var);
                printMetadata(var);
                printMaps(var);
                printer.outdent();
                printer.marginPrint("</" + type.getTypeSort().name() + ">");
            } else
                assert false : "Illegal variable base type";
            break;

        default:
            assert (false) : "Unexpected sort: " + sort.name();
            break;
        }

    }
public void
    printNode(DapNode node)
            throws IOException
    {
        if(node == null)
            return;

        DapSort sort = node.getSort();
        String dmrname = sort.getName();

        switch (sort) {
        case DATASET:// treat like group
        case GROUP:
            if(!this.ce.references(node)) break;
            DapGroup group = (DapGroup) node;
            printer.marginPrint("<" + dmrname);
            int flags = (sort == DapSort.DATASET ? PERLINE : NILFLAGS);
            printXMLAttributes(node, ce, flags);
            printer.println(">");
            printer.indent();
            // Make the output order conform to the spec
            if(group.getDimensions().size() > 0) {
                for(DapNode subnode : group.getDimensions()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            }
            if(group.getEnums().size() > 0) {
                for(DapNode subnode : group.getEnums()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            }
            if(group.getVariables().size() > 0)
                for(DapNode subnode : group.getVariables()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            printMetadata(node);
            if(group.getGroups().size() > 0)
                for(DapNode subnode : group.getGroups()) {
                    if(!this.ce.references(subnode)) continue;
                    printNode(subnode);
                    printer.eol();
                }
            printer.outdent();
            printer.marginPrint("</" + dmrname + ">");
            break;

        case DIMENSION:
            if(!this.ce.references(node)) break;
            DapDimension dim = (DapDimension) node;
            if(!dim.isShared()) break; // ignore, here, anonymous dimensions
            printer.marginPrint("<" + dmrname);
            printXMLAttributes(node, ce, NILFLAGS);
            if(dim.isUnlimited())
                printXMLAttribute(AbstractDSP.UCARTAGUNLIMITED, "1", NILFLAGS);
            if(hasMetadata(node)) {
                printer.println(">");
                printMetadata(node);
                printer.marginPrint("</" + dmrname + ">");
            } else {
                printer.print("/>");
            }
            break;

        case ENUMERATION:
            if(!this.ce.references(node)) break;
            DapEnumeration en = (DapEnumeration) node;
            printer.marginPrint("<" + dmrname);
            printXMLAttributes(en, ce, NILFLAGS);
            printer.println(">");
            printer.indent();
            List<String> econstnames = en.getNames();
            for(String econst : econstnames) {
                DapEnumConst value = en.lookup(econst);
                assert (value != null);
                printer.marginPrintln(
                        String.format("<EnumConst name=\"%s\" value=\"%d\"/>",
                                Escape.entityEscape(econst, null), value.getValue()));
            }
            printMetadata(node);
            printer.outdent();
            printer.marginPrint("</" + dmrname + ">");
            break;

        case VARIABLE:
            if(!this.ce.references(node)) break;
            DapVariable var = (DapVariable) node;
            DapType type = var.getBaseType();
            printer.marginPrint("<" + type.getTypeSort().name());
            printXMLAttributes(node, ce, NILFLAGS);
            if(type.isAtomic()) {
                if((hasMetadata(node) || hasDimensions(var) || hasMaps(var))) {
                    printer.println(">");
                    printer.indent();
                    if(hasDimensions(var))
                        printDimrefs(var);
                    if(hasMetadata(var))
                        printMetadata(var);
                    if(hasMaps(var))
                        printMaps(var);
                    printer.outdent();
                    printer.marginPrint("</" + type.getTypeSort().name() + ">");
                } else
                    printer.print("/>");
            } else if(type.getTypeSort().isCompound()) {
                DapStructure struct = (DapStructure) type;
                printer.println(">");
                printer.indent();
                for(DapVariable field : struct.getFields()) {
                    if(!this.ce.references(field)) continue;
                    printNode(field);
                    printer.eol();
                }
                printDimrefs(var);
                printMetadata(var);
                printMaps(var);
                printer.outdent();
                printer.marginPrint("</" + type.getTypeSort().name() + ">");
            } else
                assert false : "Illegal variable base type";
            break;

        default:
            assert (false) : "Unexpected sort: " + sort.name();
            break;
        }

    }
Print an arbitrary DapNode and its subnodes
as if it is being sent to a client with
optional constraint; inclusions are determined
by the view.
<p>
Handling newlines is a bit tricky because they may be
embedded for e.g. groups, enums,
etc.  So the rule is that the
last newline is elided and left
for the caller to print.
Exceptions: printMetadata
printDimrefs, printMaps

@param node - the node to print
@throws IOException Note that the PrintWriter is global.