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 
19 package org.openoffice.xmerge.merger.merge;
20 
21 import org.w3c.dom.Element;
22 import org.w3c.dom.Node;
23 
31 
40 public 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 }
static Node deepClone(Node oldNode, Node newNode)
Perform a deep clone of certain.
Definition: XmlUtil.java:42
Provides general purpose utilities.
static final int DELETE
Delete operation.
Definition: Difference.java:33
void insertNode(Node oldNode, Node newNode)
Insert.
DocumentMerge(ConverterCapabilities cc, NodeMergeAlgorithm merge)
Constructor.
void replaceElement(Element currElem, Element newElem)
Replace Element.
static final int CHANGE
Change operation.
Definition: Difference.java:36
Class containing static utility methods for handling XML trees.
Definition: XmlUtil.java:30
void removeNode(Node node)
Removes the specified.
ConverterCapabilities cc_
The capabilities of this converter.
void applyDifference(Iterator orgSeq, Iterator modSeq, Difference[] differences)
This method is to merge the difference to an.
void appendNode(Node oldNode, Node newNode)
Appends.
This is an interface for a MergeAlgorithm to merge two.
Provides interfaces for converting between two.
Definition: Convert.java:19
static final int ADD
Add operation.
Definition: Difference.java:30
void merge(Node originalNode, Node modifyNode)
This method is used to merge two given.
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a.
Definition: Iterator.java:27