public static <T extends Document & HasName, D extends Document & HasName> 
    String relativeName(
            final D document,
            final Class<T> from,
            final Name name,
            final CharSequence separator,
            final UnaryOperator<String> nameMapper) {
        
        requireNonNull(document);
        requireNonNull(from);
        requireNonNull(nameMapper);
        
        final StringJoiner sj = new StringJoiner(separator).setEmptyValue("");
        final List<HasAlias> ancestors = document.ancestors()
            .map(HasAlias::of)
            .collect(toList());

        boolean add = false;
        for (final HasAlias parent : ancestors) {
            if (add || parent.mainInterface().isAssignableFrom(from)) {
                sj.add(nameMapper.apply(name.of(parent)));
                add = true;
            }
        }
        sj.add(nameMapper.apply(name.of(HasAlias.of(document))));
        return sj.toString();
    }
Returns the relative name for the given Document up to the point given by
the parent Class by successively applying the provided nameMapper onto
the Node names and separating the names with the provided separator.
<p>
For example, {@code relativeName(column, Dbms.class)} would return the
String "dbms_name.schema_name.table_name.column_name" if the separator is
"."

@param <T>         parent type
@param <D>         Document type
@param document    to use
@param from        class
@param name        if java or database name should be used
@param separator   to use between the document names
@param nameMapper  to apply to all names encountered during traversal
@return            the relative name for this Node from the point 
                   given by the parent Class
runtime-parent/runtime-config/src/main/java/com/speedment/runtime/config/util/DocumentUtil.java