class DOMHelper {

    private DOMHelper() {
    }

    /**
     * Gets the value of the node at the given path
     * relative to the given base element.
     * For element nodes the value is the text content and for
     * the attributes node the attribute value.
     *
     * @param base base element
     * @param path path
     * @return the node value or null if no such node was found
     */
    public static String getNodeValue(Element base, Path path) {
        Node node = getElementNode(base, path);
        if (node != null) {
            if (path.attribute != null) {
                Node at = node.getAttributes().getNamedItem(path.attribute);
                return at != null ? at.getNodeValue() : null;
            } else {
                return node.getTextContent();
            }
        }
        return null;
    }

    public static void visitNodes(Context ctx, XAnnotatedList xam, Element base, Path path,
                                  NodeVisitor visitor, Collection<Object> result) {
        Node el = base;
        int len = path.segments.length - 1;
        for (int i = 0; i < len; i++) {
            el = getElementNode(el, path.segments[i]);
            if (el == null) {
                return;
            }
        }
        String name = path.segments[len];

        if (path.attribute != null) {
            visitAttributes(ctx, xam, el, name, path.attribute, visitor, result);
        } else {
            visitElements(ctx, xam, el, name, visitor, result);
        }
    }

    public static void visitAttributes(Context ctx, XAnnotatedList xam, Node base, String name,
                                       String attrName, NodeVisitor visitor,
                                       Collection<Object> result) {
        Node p = base.getFirstChild();
        while (p != null) {
            if (p.getNodeType() == Node.ELEMENT_NODE) {
                if (name.equals(p.getNodeName())) {
                    Node at = p.getAttributes().getNamedItem(attrName);
                    if (at != null) {
                        visitor.visitNode(ctx, xam, at, result);
                    }
                }
            }
            p = p.getNextSibling();
        }
    }

    public static void visitElements(Context ctx, XAnnotatedList xam, Node base, String name,
                                     NodeVisitor visitor, Collection<Object> result) {
        Node p = base.getFirstChild();
        while (p != null) {
            if (p.getNodeType() == Node.ELEMENT_NODE) {
                if (name.equals(p.getNodeName())) {
                    visitor.visitNode(ctx, xam, p, result);
                }
            }
            p = p.getNextSibling();
        }
    }

    public static void visitMapNodes(Context ctx, XAnnotatedMap xam, Element base, Path path,
                                     NodeMapVisitor visitor, Map<String, Object> result) {
        Node el = base;
        int len = path.segments.length - 1;
        for (int i = 0; i < len; i++) {
            el = getElementNode(el, path.segments[i]);
            if (el == null) {
                return;
            }
        }
        String name = path.segments[len];

        if (path.attribute != null) {
            visitMapAttributes(ctx, xam, el, name, path.attribute, visitor, result);
        } else {
            visitMapElements(ctx, xam, el, name, visitor, result);
        }
    }

    public static void visitMapAttributes(Context ctx, XAnnotatedMap xam, Node base, String name,
                                          String attrName, NodeMapVisitor visitor,
                                          Map<String, Object> result) {
        Node p = base.getFirstChild();
        while (p != null) {
            if (p.getNodeType() == Node.ELEMENT_NODE) {
                if (name.equals(p.getNodeName())) {
                    Node at = p.getAttributes().getNamedItem(attrName);
                    if (at != null) {
                        String key = getNodeValue((Element) p, xam.key);
                        if (key != null) {
                            visitor.visitNode(ctx, xam, at, key, result);
                        }
                    }
                }
            }
            p = p.getNextSibling();
        }
    }

    public static void visitMapElements(Context ctx, XAnnotatedMap xam, Node base, String name,
                                        NodeMapVisitor visitor, Map<String, Object> result) {
        Node p = base.getFirstChild();
        while (p != null) {
            if (p.getNodeType() == Node.ELEMENT_NODE) {
                if (name.equals(p.getNodeName())) {
                    String key = getNodeValue((Element) p, xam.key);
                    if (key != null) {
                        visitor.visitNode(ctx, xam, p, key, result);
                    }
                }
            }
            p = p.getNextSibling();
        }
    }

    public static Node getElementNode(Node base, String name) {
        Node node = base.getFirstChild();
        while (node != null) {
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                if (name.equals(node.getNodeName())) {
                    return node;
                }
            }
            node = node.getNextSibling();
        }
        return null;
    }

    public static Node getElementNode(Node base, Path path) {<FILL_FUNCTION_BODY>}

    public abstract static class NodeVisitor {

        public abstract void visitNode(Context ctx, XAnnotatedMember xam, Node node,
                                       Collection<Object> result);

    }

    public abstract static class NodeMapVisitor {

        public abstract void visitNode(Context ctx, XAnnotatedMember xam, Node node, String key,
                                       Map<String, Object> result);

    }

}

        Node el = base;
        int len = path.segments.length;
        for (int i = 0; i < len; i++) {
            el = getElementNode(el, path.segments[i]);
            if (el == null) {
                return null;
            }
        }
        return el;
    
<no_super_class>