4A Server -  2.0
 All Classes Namespaces Files Functions Variables Enumerator
RecursiveNodeIterator.java
Go to the documentation of this file.
1 /*
2  * Project: Server for annotations sharing
3  * Subproject: Position of fragment of text in XML document
4  * Author: Peter Bartoš
5  * Edited by: Ing. Jaroslav Dytrych idytrych@fit.vutbr.cz
6  * File: RecursiveNodeIterator.java
7  * Description: Recursive node iterator
8  */
9 
10 /**
11  * @file RecursiveNodeIterator.java
12  *
13  * @brief Recursive node iterator
14  */
15 
16 package cz.vutbr.fit.knot.annotations.fragmentUpdater.nodeIterators;
17 
19 import javax.xml.xpath.XPathExpression;
20 import javax.xml.xpath.XPathExpressionException;
21 import org.w3c.dom.Document;
22 import org.w3c.dom.Node;
23 
24 /**
25  * Recursive node iterator
26  *
27  * @brief Recursive node iterator
28  * @author Peter Bartoš
29  */
30 public class RecursiveNodeIterator extends NodeIterator {
31 
32  protected Node nextNode;
33  protected boolean firstNode;
34  protected long timestamp;
35 
36  /**
37  * Overriden init() method
38  *
39  * @param document document whose nodes will be iterated through
40  * @param expr XPath expression according to which iterating will be provided
41  */
42  @Override
43  public void init(Document document, XPathExpression expr) throws XPathExpressionException {
44 
45  timestamp = System.currentTimeMillis();
46 
47  this.document = document;
48  this.nodeList = XPathHelper.evaluateXPath(document, expr);
49  this.currentNodeIndex = 0;
50  firstNode = true;
51 
52  if (nodeList.getLength() == 0) {
53  nextNode = null;
54  } else {
55  // First node which will be parsed
56  nextNode = nodeList.item(currentNodeIndex);
57  while (nextNode.hasChildNodes()) {
58  nextNode = nextNode.getFirstChild();
59  }
60  }
61  } // init()
62 
63  /**
64  *
65  * Method for getting iterator's next node, recursive strategy is used.
66  *
67  * @return iterator's next node
68  */
69  @Override
70  public Node nextNode() {
71 
72  Node resultNode, newNextNode;
73 
74  // There is no more node
75  if (nextNode == null) {
76  return null;
77  }
78 
79  // First node is special, can be in the middle
80  // After first node returned, begin from the 1st sibling in the level
81  if (firstNode) {
82  firstNode = false;
83  resultNode = nextNode;
84  nextNode = nextNode.getParentNode().getFirstChild();
85  return resultNode;
86  }
87 
88  // If it is a terminal node
89  if (!nextNode.hasChildNodes()) {
90  resultNode = nextNode;
91  newNextNode = nextNode.getNextSibling();
92 
93  // If there is no sibling
94  if (newNextNode == null) {
95  // Parent of this node is now depleted
96  setVisited(nextNode.getParentNode());
97 
98  // Default Next node is parent node
99  nextNode = nextNode.getParentNode();
100 
101  // If there is a possibility, start from first node on parent level
102  if (nextNode.getParentNode() != null) {
103  nextNode = nextNode.getParentNode().getFirstChild();
104  }
105  } else {
106  nextNode = newNextNode;
107  }
108 
109  if (resultNode.getNodeName().equals("#text") && !isWhitespaced(resultNode.getTextContent())) {
110  return resultNode;
111  }
112 
113  return nextNode();
114 
115  } else { // Some parent node
116 
117  if (isVisited(nextNode)) {
118 
119  newNextNode = nextNode.getNextSibling();
120 
121  if (newNextNode == null) {
122  setVisited(nextNode.getParentNode()); // This parent node depleted
123  nextNode = nextNode.getParentNode();
124  } else {
125  nextNode = newNextNode;
126  }
127 
128  return nextNode();
129 
130  } else { // node not visited
131  nextNode = nextNode.getFirstChild();
132 
133  // Inception: Go deeper to the terminal node
134  while (nextNode.hasChildNodes()) {
135  nextNode = nextNode.getFirstChild();
136  }
137 
138  return nextNode();
139  }
140  } // Some parent node
141  } // nextNode()
142 
143  /**
144  * Sets node's "visited" flag
145  *
146  * @param node node which flag is to be set
147  */
148  private void setVisited(Node node) {
149  if (node == null) {
150  return;
151  }
152 
153  node.setUserData("visited", timestamp, null);
154  }
155 
156  /**
157  * Getter of node's "visited" flag
158  *
159  * @param node node which flag is to be returned
160  * @return true if "visited" flag is set, false if isn't
161  */
162  private boolean isVisited(Node node) {
163  if (node == null) {
164  return true;
165  }
166 
167  Long visited = (Long) node.getUserData("visited");
168  if (visited == null) {
169  return false;
170  }
171 
172  return (visited == timestamp);
173  }
174 
175  /**
176  * Finds out if string is consists of whitespaces
177  *
178  * @param string string to be examined
179  * @return true if is whitespace, false if not
180  */
181  protected boolean isWhitespaced(String string) {
182  return string.matches("\\s+");
183  }
184 
185  /**
186  * Overriden toString() method
187  *
188  * @return string representation of class
189  */
190  @Override
191  public String toString() {
192  return "Recursive";
193  }
194 } // class RecursiveNodeIterator