in impl/maven-xml/src/main/java/org/apache/maven/internal/xml/DefaultXmlService.java [217:379]
public XmlNode doMerge(XmlNode dominant, XmlNode recessive, Boolean childMergeOverride) {
// TODO: share this as some sort of assembler, implement a walk interface?
if (recessive == null) {
return dominant;
}
if (dominant == null) {
return recessive;
}
boolean mergeSelf = true;
String selfMergeMode = getSelfCombinationMode(dominant);
if (SELF_COMBINATION_OVERRIDE.equals(selfMergeMode)) {
mergeSelf = false;
}
if (mergeSelf) {
String value = dominant.value();
Object location = dominant.inputLocation();
Map<String, String> attrs = dominant.attributes();
List<XmlNode> children = null;
for (Map.Entry<String, String> attr : recessive.attributes().entrySet()) {
String key = attr.getKey();
if (isEmpty(attrs.get(key))) {
if (attrs == dominant.attributes()) {
attrs = new HashMap<>(attrs);
}
attrs.put(key, attr.getValue());
}
}
if (!recessive.children().isEmpty()) {
boolean mergeChildren = true;
if (childMergeOverride != null) {
mergeChildren = childMergeOverride;
} else {
String childCombinationMode = getChildCombinationMode(attrs);
if (CHILDREN_COMBINATION_APPEND.equals(childCombinationMode)) {
mergeChildren = false;
}
}
Map<String, Iterator<XmlNode>> commonChildren = new HashMap<>();
Set<String> names =
recessive.children().stream().map(XmlNode::name).collect(Collectors.toSet());
for (String name : names) {
List<XmlNode> dominantChildren = dominant.children().stream()
.filter(n -> n.name().equals(name))
.toList();
if (!dominantChildren.isEmpty()) {
commonChildren.put(name, dominantChildren.iterator());
}
}
String keysValue = recessive.attribute(KEYS_COMBINATION_MODE_ATTRIBUTE);
int recessiveChildIndex = 0;
for (XmlNode recessiveChild : recessive.children()) {
String idValue = recessiveChild.attribute(ID_COMBINATION_MODE_ATTRIBUTE);
XmlNode childDom = null;
if (!isEmpty(idValue)) {
for (XmlNode dominantChild : dominant.children()) {
if (idValue.equals(dominantChild.attribute(ID_COMBINATION_MODE_ATTRIBUTE))) {
childDom = dominantChild;
// we have a match, so don't append but merge
mergeChildren = true;
}
}
} else if (!isEmpty(keysValue)) {
String[] keys = keysValue.split(",");
Map<String, Optional<String>> recessiveKeyValues = Stream.of(keys)
.collect(Collectors.toMap(
k -> k, k -> Optional.ofNullable(recessiveChild.attribute(k))));
for (XmlNode dominantChild : dominant.children()) {
Map<String, Optional<String>> dominantKeyValues = Stream.of(keys)
.collect(Collectors.toMap(
k -> k, k -> Optional.ofNullable(dominantChild.attribute(k))));
if (recessiveKeyValues.equals(dominantKeyValues)) {
childDom = dominantChild;
// we have a match, so don't append but merge
mergeChildren = true;
}
}
} else {
childDom = dominant.child(recessiveChild.name());
}
if (mergeChildren && childDom != null) {
String name = recessiveChild.name();
Iterator<XmlNode> it =
commonChildren.computeIfAbsent(name, n1 -> Stream.of(dominant.children().stream()
.filter(n2 -> n2.name().equals(n1))
.collect(Collectors.toList()))
.filter(l -> !l.isEmpty())
.map(List::iterator)
.findFirst()
.orElse(null));
if (it == null) {
if (children == null) {
children = new ArrayList<>(dominant.children());
}
children.add(recessiveChild);
} else if (it.hasNext()) {
XmlNode dominantChild = it.next();
String dominantChildCombinationMode = getSelfCombinationMode(dominantChild);
if (SELF_COMBINATION_REMOVE.equals(dominantChildCombinationMode)) {
if (children == null) {
children = new ArrayList<>(dominant.children());
}
children.remove(dominantChild);
} else {
int idx = dominant.children().indexOf(dominantChild);
XmlNode merged = merge(dominantChild, recessiveChild, childMergeOverride);
if (merged != dominantChild) {
if (children == null) {
children = new ArrayList<>(dominant.children());
}
children.set(idx, merged);
}
}
}
} else {
if (children == null) {
children = new ArrayList<>(dominant.children());
}
int idx = mergeChildren ? children.size() : recessiveChildIndex;
children.add(idx, recessiveChild);
}
recessiveChildIndex++;
}
}
if (value != null || attrs != dominant.attributes() || children != null) {
if (children == null) {
children = dominant.children();
}
if (!Objects.equals(value, dominant.value())
|| !Objects.equals(attrs, dominant.attributes())
|| !Objects.equals(children, dominant.children())
|| !Objects.equals(location, dominant.inputLocation())) {
return XmlNode.newBuilder()
.prefix(dominant.prefix())
.namespaceUri(dominant.namespaceUri())
.name(dominant.name())
.value(value != null ? value : dominant.value())
.attributes(attrs)
.children(children)
.inputLocation(location)
.build();
} else {
return dominant;
}
}
}
return dominant;
}