LibreOffice Module xmerge (master) 1
DocumentMerge.java
Go to the documentation of this file.
1/*
2 * This file is part of the LibreOffice project.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * This file incorporates work covered by the following license notice:
9 *
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
17 */
18
19package org.openoffice.xmerge.merger.merge;
20
21import org.w3c.dom.Element;
22import org.w3c.dom.Node;
23
31
40public class DocumentMerge implements MergeAlgorithm {
41
43
46
54 cc_ = cc;
55 subDocumentMerge = merge;
56 }
57
58 public void applyDifference(Iterator orgSeq, Iterator modSeq,
59 Difference[] differences) throws MergeException {
60
61 // a quick test whether the differences array is in ascending order
62 int currentPosition = -1;
63 boolean haveDeleteOperation = false;
64
65 for (Difference difference : differences) {
66 if (difference.getOrgPosition() > currentPosition) {
67 currentPosition = difference.getOrgPosition();
68 haveDeleteOperation = difference.getOperation() == Difference.DELETE;
69 } else if (difference.getOrgPosition() == currentPosition) {
70 if (difference.getOperation() == Difference.DELETE) {
71 haveDeleteOperation = true;
72 } else if (difference.getOperation() == Difference.ADD &&
73 haveDeleteOperation) {
74 throw new MergeException(
75 "Differences array is not sorted. Delete before Add");
76 }
77 } else {
78 throw new MergeException("Differences array need to be sorted.");
79 }
80 }
81
82 // reset sequence counters
83 orgSeq.start();
84 int orgSeqCounter = 0;
85
86 modSeq.start();
87 int modSeqCounter = 0;
88
89 // check for each diff unit in the diff array to apply the diff
90 for (Difference currentDiff : differences) {
91
92 int operation = currentDiff.getOperation();
93
94 switch (operation) {
95
96 case Difference.DELETE:
97 // loop through the original sequence up to the expected
98 // position. note that we use delta (see above comment)
99 // also. we will just continue the counter without reset it.
100 for (;
101 orgSeqCounter < currentDiff.getOrgPosition();
102 orgSeqCounter++, orgSeq.next()) {
103 // empty
104 }
105
106 // remove the Node. note that it will NOT affect the
107 // iterator sequence as ParaNodeIterator is a static one.
108 removeNode((Node)(orgSeq.currentElement()));
109
110 break;
111
112 // if it's an add operation, then get content from original seq
113 case Difference.ADD:
114 // loop through the modified sequence up to the expected
115 // position to get the content. As we don't need to modify
116 // the sequence. we don't need to use delta to do adjustment.
117 for (;
118 modSeqCounter < currentDiff.getModPosition();
119 modSeqCounter++, modSeq.next()) {
120 // empty
121 }
122
123 for (;
124 orgSeqCounter < currentDiff.getOrgPosition();
125 orgSeqCounter++, orgSeq.next()) {
126 // empty
127 }
128
129 if (orgSeqCounter > orgSeq.elementCount() - 1) {
130 // append the element to the end of the original sequence
131 appendNode((Node)(orgSeq.currentElement()),
132 (Node)(modSeq.currentElement()));
133 } else {
134 // insert the element BEFORE the current element
135 insertNode((Node)(orgSeq.currentElement()),
136 (Node)(modSeq.currentElement()));
137 }
138
139 break;
140
141 case Difference.CHANGE:
142 for (;
143 modSeqCounter < currentDiff.getModPosition();
144 modSeqCounter++, modSeq.next()) {
145 // empty
146 }
147
148 for (;
149 orgSeqCounter < currentDiff.getOrgPosition();
150 orgSeqCounter++, orgSeq.next()) {
151 // empty
152 }
153
154 if (subDocumentMerge == null) {
155 // use a simple replace if no row merge algorithm supply
156 replaceElement((Element)orgSeq.currentElement(),
157 (Element)modSeq.currentElement());
158 } else {
159 subDocumentMerge.merge((Element)orgSeq.currentElement(),
160 (Element)modSeq.currentElement());
161
162 }
163 break;
164
165 default:
166 break;
167 }
168 }
169 }
170
176 protected void removeNode(Node node) {
177
178 Node parent = node.getParentNode();
179 parent.removeChild(node);
180 }
181
188 private void appendNode(Node oldNode, Node newNode) {
189 Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
190 Node parent = oldNode.getParentNode();
191 parent.appendChild(clonedNode);
192 }
193
200 private void insertNode(Node oldNode, Node newNode) {
201 Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
202 Node parent = oldNode.getParentNode();
203 parent.insertBefore(clonedNode, oldNode);
204 }
205
212 private void replaceElement(Element currElem, Element newElem) {
213
214 Node clonedNode = XmlUtil.deepClone(currElem, newElem);
215 Node parent = currElem.getParentNode();
216 parent.replaceChild(clonedNode, currElem);
217 }
218}
This Exception is thrown by merge algorithms.
This is the Difference basic unit.
Definition: Difference.java:27
static final int CHANGE
Change operation.
Definition: Difference.java:36
static final int DELETE
Delete operation.
Definition: Difference.java:33
static final int ADD
Add operation.
Definition: Difference.java:30
This is an implementation of the MergeAlgorithm interface.
void insertNode(Node oldNode, Node newNode)
Insert Node before the specified Node.
ConverterCapabilities cc_
The capabilities of this converter.
void appendNode(Node oldNode, Node newNode)
Appends Node after the specified Node.
void removeNode(Node node)
Removes the specified Node.
void replaceElement(Element currElem, Element newElem)
Replace Element.
void applyDifference(Iterator orgSeq, Iterator modSeq, Difference[] differences)
This method is to merge the difference to an Iterator.
DocumentMerge(ConverterCapabilities cc, NodeMergeAlgorithm merge)
Constructor.
Class containing static utility methods for handling XML trees.
Definition: XmlUtil.java:30
static Node deepClone(Node oldNode, Node newNode)
Perform a deep clone of certain Node which will base on the document Node of the old Node.
Definition: XmlUtil.java:42
A ConverterCapabilities object is used by DocumentMerger implementations.
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a Document.
Definition: Iterator.java:27
This is the MergeAlgorithm interface.
This is an interface for a MergeAlgorithm to merge two Node objects.
void merge(Node originalNode, Node modifyNode)
This method is used to merge two given Node objects.
The DiffAlgorithm and MergeAlgorithm are used to provide the merge capabilities of this project.
Provides general purpose utilities.
Provides interfaces for converting between two Document formats, and supports a "merge" interface for...
Definition: Convert.java:19