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 
19 package org.openoffice.xmerge.merger.diff;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
28 import org.w3c.dom.NamedNodeMap;
29 import org.w3c.dom.Node;
30 import org.w3c.dom.NodeList;
31 
44 public abstract class NodeIterator implements Iterator {
45 
46  private List<Node> nodeList = null;
47  private int currentPosition = 0;
48  private final Node root;
49  private final ConverterCapabilities cc_;
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) {
66  currentPosition++;
67  return currentElement();
68  } else {
69  return null;
70  }
71  }
72 
73  public Object previous() {
74  if (currentPosition > 0) {
75  currentPosition--;
76  return currentElement();
77  } else {
78  return null;
79  }
80  }
81 
82  public Object start() {
83  currentPosition = 0;
84  return currentElement();
85  }
86 
87  public Object end() {
88  int size = nodeList.size();
89 
90  if (size > 0) {
91  currentPosition = size - 1;
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 }
static final int INFO
Informational messages.
Definition: Debug.java:42
Provides a singleton resource class for converter messages.
Definition: Resources.java:37
boolean compareNode(Node node1, Node node2)
Used to compare two.
boolean canConvertAttribute(String tag, String attribute)
Test to see if the device document format supports the tag attribute in question. ...
Provides general purpose utilities.
boolean attributesEqual(Node node1, Node node2)
Compare attributes of two.
static void log(int flag, String msg)
Log message based on the flag type.
Definition: Debug.java:205
String getString(String key)
This method returns the corresponding.
Definition: Resources.java:71
This is an implementation of the.
boolean childrenEqual(Node node1, Node node2)
Compare the children of two.
boolean equivalent(Object obj1, Object obj2)
A method to allow the difference algorithm to test whether the.
static final int ERROR
Error messages.
Definition: Debug.java:44
exports com.sun.star. java
std::enable_if_t< std::is_signed_v< T1 > &&std::is_signed_v< T2 >, bool > equal(T1 value1, T2 value2)
int i
static synchronized Resources getInstance()
This method returns the singleton instance of this class.
Definition: Resources.java:47
size
boolean canConvertTag(String tag)
Test to see if the device document format supports the tag in question.
abstract boolean nodeSupported(Node node)
Check whether a.
Object currentElement()
Return the current element.
NodeIterator(ConverterCapabilities cc, Node node)
Standard constructor.
Object next()
Move to next element in the sequence.
int elementCount()
Return the total element count in the sequence.
Provides interfaces for converting between two.
Definition: Convert.java:19
This class is used for logging debug messages.
Definition: Debug.java:39
Object start()
Move to the beginning of the sequence.
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a.
Definition: Iterator.java:27