public XmlNode doMerge()

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;
    }