/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.util.xml; import com.liferay.util.xml.descriptor.XMLDescriptor; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; /** * @author Brian Wing Shun Chan * @author Alan Zimmerman * @author Jorge Ferrer */ public class XMLMerger { public XMLMerger(XMLDescriptor descriptor) { _descriptor = descriptor; } public XMLElementComparator getElementComparator() { return new XMLElementComparator(_descriptor); } public Document merge(Document masterDocument, Document slaveDocument) { Document mergedDocument = (Document)masterDocument.clone(); Element mergedRootElement = mergedDocument.getRootElement(); Element slaveRootElement = slaveDocument.getRootElement(); for (Element slaveElement : (List<Element>)slaveRootElement.elements()) { Element clonedSlaveElement = (Element)slaveElement.clone(); clonedSlaveElement.detach(); mergedRootElement.add(clonedSlaveElement); } organizeXML(mergedDocument); return mergedDocument; } public void organizeXML(Document document) { Element rootElement = document.getRootElement(); _orderChildren(rootElement, _descriptor.getRootChildrenOrder()); _mergeDuplicateElements(rootElement, getElementComparator()); } private void _addChildren( Element firstElement, Collection<Element> childElements) { List<Element> elements = firstElement.elements(); for (Element childElement : childElements) { elements.add((Element)childElement.clone()); } _orderChildren( firstElement, _descriptor.getChildrenOrder(firstElement)); } private boolean _containsObjectEqualTo( Element element, List<Element> elements, ElementComparator elementComparator) { for (Element curElement : elements) { if (elementComparator.compare(element, curElement) == 0) { return true; } } return false; } private Element _findObjectEqualTo( Element element, List<Element> elements, ElementComparator elementComparator) { for (Element curElement : elements) { if (elementComparator.compare(element, curElement) == 0) { return curElement; } } return element; } private void _mergeDuplicateElements( Element element, ElementComparator elementComparator) { List<Element> childElements = element.elements(); if (childElements.isEmpty()) { return; } List<Element> originalElements = new ArrayList<>(); List<Element> duplicateElements = new ArrayList<>(); for (int i = 0; i < childElements.size(); i++) { Element childElement = childElements.get(i); if (_containsObjectEqualTo( childElement, originalElements, elementComparator)) { if (_descriptor.canJoinChildren(childElement)) { Element firstElement = _findObjectEqualTo( childElement, originalElements, elementComparator); _addChildren(firstElement, childElement.elements()); } duplicateElements.add(childElement); } else { originalElements.add(childElement); } _orderChildren( childElement, _descriptor.getChildrenOrder(childElement)); } for (Element duplicateElement : duplicateElements) { duplicateElement.detach(); } for (Element childElement : originalElements) { _mergeDuplicateElements(childElement, elementComparator); } } private void _orderChildren( Element parentElement, String[] orderedChildrenNames) { if (orderedChildrenNames == null) { return; } List<Element> elements = new ArrayList<>(); for (int i = 0; i < orderedChildrenNames.length; i++) { elements.addAll(parentElement.elements(orderedChildrenNames[i])); } for (Element element : elements) { element.detach(); parentElement.add(element); } } private final XMLDescriptor _descriptor; }