Element (@NotNull Element to, @NotNull Element from, @NotNull List<MergeAttribute> mergeByAttributes) { for (Iterator<Element> iterator = from.getChildren().iterator(); iterator.hasNext(); ) { Element child = iterator.next(); iterator.remove(); Element existingChild = to.getChild(child.getName()); if (existingChild != null && isEmpty(existingChild)) { // replace empty tag to.removeChild(child.getName()); existingChild = null; } // if no children (e.g. `<module fileurl="value" />`), it means that element should be added as list item if (existingChild == null || existingChild.getChildren().isEmpty() || !areAttributesEqual(getAttributes(existingChild), getAttributes(child), existingChild, mergeByAttributes)) { to.addContent(child); } else { deepMergeWithAttributes(existingChild, child, mergeByAttributes); } } for (Iterator<Attribute> iterator = getAttributes(from).iterator(); iterator.hasNext(); ) { Attribute attribute = iterator.next(); iterator.remove(); to.setAttribute(attribute); } return to; }