LibreOffice Module xmerge (master) 1
NodeIterator.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.diff;
20
21import java.util.ArrayList;
22import java.util.List;
23
28import org.w3c.dom.NamedNodeMap;
29import org.w3c.dom.Node;
30import org.w3c.dom.NodeList;
31
44public abstract class NodeIterator implements Iterator {
45
46 private List<Node> nodeList = null;
47 private int currentPosition = 0;
48 private final Node root;
50
57 public NodeIterator(ConverterCapabilities cc, Node node) {
58 cc_ = cc;
59 nodeList = new ArrayList<Node>();
60 root = node;
61 markTree(node);
62 }
63
64 public Object next() {
65 if (currentPosition < nodeList.size() - 1) {
67 return currentElement();
68 } else {
69 return null;
70 }
71 }
72
73 public Object previous() {
74 if (currentPosition > 0) {
76 return currentElement();
77 } else {
78 return null;
79 }
80 }
81
82 public Object start() {
84 return currentElement();
85 }
86
87 public Object end() {
88 int size = nodeList.size();
89
90 if (size > 0) {
92 return currentElement();
93 } else {
94 return null;
95 }
96 }
97
99 if (currentPosition < 0 || currentPosition >= nodeList.size()) {
100 return null;
101 }
102 return nodeList.get(currentPosition);
103 }
104
105 public int elementCount() {
106 return nodeList.size();
107 }
108
109 public boolean equivalent(Object obj1, Object obj2) {
110 boolean equal = false;
111 if (!(obj1 instanceof Node && obj2 instanceof Node)) {
112 String errMsg = Resources.getInstance().getString("NOT_NODE_ERROR");
113 Debug.log(Debug.ERROR, errMsg);
114 } else {
115 Node node1 = (Node)obj1;
116 Node node2 = (Node)obj2;
117
118 equal = compareNode(node1, node2);
119 }
120 return equal;
121 }
122
123 public void refresh() {
124 nodeList = new ArrayList<Node>();
125 markTree(root);
126 currentPosition = 0;
127 }
128
138 protected boolean compareNode(Node node1, Node node2) {
139 boolean equal = false;
140
141 nodeCheck: {
142
143 if (node1 == null || node2 == null) {
144 break nodeCheck;
145 }
146
147 // nodevalue is short
148 if (node1.getNodeType() != node2.getNodeType()) {
149 break nodeCheck;
150 }
151
152 // nodeName will not be null
153 if (!node1.getNodeName().equals(node2.getNodeName())) {
154 break nodeCheck;
155 }
156
157 // nodeValue can be null for a lot of type of cells
158 if (node1.getNodeValue() == null && node2.getNodeValue() == null) {
159 // empty
160 } else if (node1.getNodeValue() == null ||
161 node2.getNodeValue() == null) {
162 break nodeCheck;
163 } else if (!node1.getNodeValue().equals(node2.getNodeValue())) {
164 break nodeCheck;
165 }
166
167 // try to compare attributes
168 if (!attributesEqual(node1, node2)) {
169 break nodeCheck;
170 }
171
172 // don't need to compare if both node do not have children
173 if (!node1.hasChildNodes() && !node2.hasChildNodes()) {
174 equal = true;
175 break nodeCheck;
176 // don't need to compare if one node has children but not the other
177 } else if (!node1.hasChildNodes() || !node2.hasChildNodes()) {
178 equal = false;
179 break nodeCheck;
180 // need to compare if both node has children
181 } else if (!childrenEqual(node1, node2)) {
182 break nodeCheck;
183 }
184
185 equal = true;
186 }
187
188 return equal;
189 }
190
203 protected boolean childrenEqual(Node node1, Node node2) {
204
205 boolean equal = false;
206
207 childrenCheck: {
208 NodeList node1Children = node1.getChildNodes();
209 NodeList node2Children = node2.getChildNodes();
210
211 if (node1Children == null || node2Children == null) {
212 break childrenCheck;
213 }
214
215 if (node1Children.getLength() != node2Children.getLength()) {
216 break childrenCheck;
217 }
218
219 // compare all the children
220 equal = true;
221
222 for (int i = 0; i < node1Children.getLength(); i++) {
223 if (!compareNode(node1Children.item(i),
224 node2Children.item(i))) {
225 equal = false;
226 break childrenCheck;
227 }
228 }
229 }
230
231 return equal;
232 }
233
246 private boolean attributesEqual(Node node1, Node node2) {
247
248 boolean equal = false;
249 String nodeName = node1.getNodeName();
250 NamedNodeMap attrNode[] = new NamedNodeMap[2];
251 attrNode[0] = node1.getAttributes();
252 attrNode[1] = node2.getAttributes();
253
254 // Attribute node will be null if node is not an element node
255 // and attribute nodes are equal if both are not element node
256 if (attrNode[0] == null || attrNode[1] == null) {
257 if (attrNode[0] == null && attrNode[1] == null) {
258 equal = true;
259 }
260 return equal;
261 }
262
263 // Compare the attributes from node1 vs node2 and node2 vs node1
264 // though it's a little inefficient for the duplication of comparison
265 // as the number of attributes is not so many, it should not be
266 // a big problem.
267 int len [] = new int[2];
268 int src, dst;
269
270 attrCheck: {
271 for (int i = 0; i < 2; i++) {
272
273 if (i == 0) {
274 src = 0;
275 dst = 1;
276 } else {
277 src = 1;
278 dst = 0;
279 }
280
281 len[src] = attrNode[src].getLength();
282
283 for (int j = 0; j < len[src]; j++) {
284 Node srcAttr = attrNode[src].item(j);
285 String srcAttrName = srcAttr.getNodeName();
286
287 // copy the supported attrs
288 if (cc_ == null ||
289 cc_.canConvertAttribute(nodeName, srcAttrName)) {
290
291 // check whether the attribute exist in dst node
292 Node dstAttr = attrNode[dst].getNamedItem(srcAttrName);
293
294 if (dstAttr == null) {
296 "[NodeIterator] Attr not exist in dst - "
297 + srcAttrName);
298 break attrCheck;
299 }
300
301 // then compare the attribute values
302 if (!srcAttr.getNodeValue().equals(
303 dstAttr.getNodeValue())) {
305 "[NodeIterator] Attr diff src: " +
306 srcAttr.getNodeValue() + " dst: "+
307 dstAttr.getNodeValue());
308 break attrCheck;
309 }
310 } // end if cc_ loop
311 } // end for j loop
312 } // end for i loop
313
314 // the whole checking is done smoothly and all attributes are equal
315 equal = true;
316 }
317
318 return equal;
319 }
320
333 protected abstract boolean nodeSupported(Node node);
334
335 // doing a depth first search for the tree and mark all supported nodes
336 private void markTree(Node node) {
337
338 // if this is a supported node, then we add it to our cache table
339 if (nodeSupported(node)) {
340 nodeList.add(node);
341 } else {
342 // or we go through all children nodes recursively
343 // (can be optimized in future)
344 String nodeName = node.getNodeName();
345 if ( cc_ == null || cc_.canConvertTag(nodeName)) {
346 NodeList auxNodeList = node.getChildNodes();
347 int nodeListLength = auxNodeList.getLength();
348 for (int i = 0; i < nodeListLength; i++) {
349 markTree(auxNodeList.item(i));
350 }
351 }
352 else {
353 Debug.log(Debug.INFO, " [NodeIterator::markTree] Skipping node "
354 + nodeName);
355 }
356 }
357 }
358}
This is an implementation of the Iterator interface.
boolean compareNode(Node node1, Node node2)
Used to compare two Node objects (type/name/value) and all their children Node objects.
boolean childrenEqual(Node node1, Node node2)
Compare the children of two Node objects.
boolean equivalent(Object obj1, Object obj2)
A method to allow the difference algorithm to test whether the obj1 and obj2 in the Iterator are cons...
abstract boolean nodeSupported(Node node)
Check whether a Node is supported.
Object start()
Move to the beginning of the sequence.
boolean attributesEqual(Node node1, Node node2)
Compare attributes of two Node objects.
void refresh()
A method to force the Iterator to traverse the tree again to refresh the content.
Object currentElement()
Return the current element Object content.
Object next()
Move to next element in the sequence.
int elementCount()
Return the total element count in the sequence.
NodeIterator(ConverterCapabilities cc, Node node)
Standard constructor.
This class is used for logging debug messages.
Definition: Debug.java:39
static final int INFO
Informational messages.
Definition: Debug.java:42
static void log(int flag, String msg)
Log message based on the flag type.
Definition: Debug.java:205
static final int ERROR
Error messages.
Definition: Debug.java:44
Provides a singleton resource class for converter messages.
Definition: Resources.java:38
static synchronized Resources getInstance()
This method returns the singleton instance of this class.
Definition: Resources.java:47
String getString(String key)
This method returns the corresponding String given the key.
Definition: Resources.java:71
A ConverterCapabilities object is used by DocumentMerger implementations.
boolean canConvertAttribute(String tag, String attribute)
Test to see if the device document format supports the tag attribute in question.
boolean canConvertTag(String tag)
Test to see if the device document format supports the tag in question.
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a Document.
Definition: Iterator.java:27
bool equal(T const &rfValA, T const &rfValB)
size
int i
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