1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml.sxc;
25 
26 import org.w3c.dom.Node;
27 import org.w3c.dom.Element;
28 import org.w3c.dom.NodeList;
29 
30 import org.openoffice.xmerge.Document;
31 import org.openoffice.xmerge.DocumentMerger;
32 import org.openoffice.xmerge.MergeException;
33 import org.openoffice.xmerge.ConverterCapabilities;
34 import org.openoffice.xmerge.converter.xml.OfficeConstants;
35 import org.openoffice.xmerge.merger.DiffAlgorithm;
36 import org.openoffice.xmerge.merger.Difference;
37 import org.openoffice.xmerge.merger.Iterator;
38 import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
39 import org.openoffice.xmerge.merger.diff.IteratorRowCompare;
40 import org.openoffice.xmerge.merger.diff.RowIterator;
41 import org.openoffice.xmerge.merger.merge.SheetMerge;
42 import org.openoffice.xmerge.merger.merge.PositionBaseRowMerge;
43 import org.openoffice.xmerge.merger.MergeAlgorithm;
44 import org.openoffice.xmerge.util.XmlUtil;
45 import org.openoffice.xmerge.util.Debug;
46 
47 
48 /**
49  *  Generic small device implementation of <code>DocumentMerger</code> for
50  *  the {@link
51  *  org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
52  *  SxcPluginFactory}.  Used with SXC <code>Document</code> objects.
53  */
54 public class DocumentMergerImpl implements DocumentMerger {
55 
56     private ConverterCapabilities cc_;
57     private org.openoffice.xmerge.Document orig = null;
58 
59     /**
60      *  Constructor
61      *
62      *  @param  doc  The original &quot;Office&quot; <code>Document</code>
63      *               to merge.
64      *  @param  cc   The <code>ConverterCapabilities</code>.
65      */
DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc)66     public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
67         cc_ = cc;
68         this.orig = doc;
69     }
70 
merge(Document modifiedDoc)71     public void merge(Document modifiedDoc) throws MergeException {
72 
73         SxcDocument sdoc1 = (SxcDocument)orig;
74         SxcDocument sdoc2 = (SxcDocument)modifiedDoc;
75 
76         org.w3c.dom.Document doc1 = sdoc1.getContentDOM();
77         org.w3c.dom.Document doc2 = sdoc2.getContentDOM();
78 
79         Element elem1 = doc1.getDocumentElement();
80         Element elem2 = doc2.getDocumentElement();
81 
82         // get table name
83         NodeList workSheetList1 =
84             elem1.getElementsByTagName(OfficeConstants.TAG_TABLE);
85         NodeList workSheetList2 =
86             elem2.getElementsByTagName(OfficeConstants.TAG_TABLE);
87 
88         int numOfWorkSheet = workSheetList1.getLength();
89 
90         for (int i=0; i < numOfWorkSheet; i++) {
91             Node workSheet = workSheetList1.item(i);
92 
93             // try to match the workSheet
94             Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList2);
95 
96             if (matchingWorkSheet != null) {
97 
98                 // need to put it into a row Iterator
99                 // use a straight comparsion algorithm then do a merge on it
100                 Iterator i1 = new RowIterator(cc_, workSheet);
101                 Iterator i2 = new RowIterator(cc_, matchingWorkSheet);
102 
103                 // find out the diff
104                 DiffAlgorithm diffAlgo = new IteratorRowCompare();
105 
106                 // find out the paragrah level diffs
107                 Difference[] diffResult = diffAlgo.computeDiffs(i1, i2);
108 
109                 if (Debug.isFlagSet(Debug.INFO)) {
110                     Debug.log(Debug.INFO, "Diff Result: ");
111 
112                     for (int j = 0; j < diffResult.length; j++) {
113                         Debug.log(Debug.INFO, diffResult[j].debug());
114                     }
115                 }
116 
117                 // merge back the result
118                 NodeMergeAlgorithm rowMerger = new PositionBaseRowMerge(cc_);
119                 MergeAlgorithm merger = new SheetMerge(cc_, rowMerger);
120 
121                 Iterator result = null;
122 
123                 merger.applyDifference(i1, i2, diffResult);
124             }
125         }
126 
127         numOfWorkSheet = workSheetList2.getLength();
128 
129         // for those workSheet from target don't have a matching one
130         // in the original workSheet list, we add it
131 
132         // find out the office body node first
133         NodeList officeBodyList =
134             elem1.getElementsByTagName(OfficeConstants.TAG_OFFICE_BODY);
135 
136         Node officeBody = officeBodyList.item(0);
137 
138         // for each WorkSheets, try to see whether we have it or not
139         for (int j=0; j < numOfWorkSheet; j++) {
140             Node workSheet= workSheetList2.item(j);
141 
142             // try to match the workSheet
143             //
144             Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList1);
145 
146             // add the new WorkSheet to the original document iff match not
147             // found
148             //
149             if (matchingWorkSheet == null) {
150                 Node cloneNode = XmlUtil.deepClone(officeBody, workSheet);
151                 officeBody.appendChild(cloneNode);
152             }
153         }
154     }
155 
156     /**
157      *  Try to find a WorkSheet from the modified WorkSheetList that
158      *  has a matching table name from the original WorkSheet.
159      *
160      *  @param  orgSheet      The original WorkSheet.
161      *  @param  modSheetList  The modified WorkSheet.
162      *
163      *  @return  The Node in modSheetList that matches the orgSheet.
164      */
matchWorkSheet(Node orgSheet, NodeList modSheetList)165     private Node matchWorkSheet(Node orgSheet, NodeList modSheetList) {
166 
167         Node matchSheet = null;
168 
169         String orgTableName = ((Element)orgSheet).getAttribute(
170                             OfficeConstants.ATTRIBUTE_TABLE_NAME);
171 
172         if (orgTableName == null)
173             return null;
174 
175         int numOfWorkSheet = modSheetList.getLength();
176 
177         String modTableName;
178 
179         for (int i=0; i < numOfWorkSheet; i++) {
180             modTableName = ((Element)modSheetList.item(i)).getAttribute(
181                             OfficeConstants.ATTRIBUTE_TABLE_NAME);
182             if (modTableName == null)
183                 continue;
184 
185             if (orgTableName.equals(modTableName)) {
186                 matchSheet = modSheetList.item(i);
187                 break;
188             }
189         }
190 
191         return matchSheet;
192     }
193 }
194 
195