4A Server -  2.0
 All Classes Namespaces Files Functions Variables Enumerator
BidirectionallyUnNestNodeIterator.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: Bc. Lukas Kubik xkubik22@stud.fit.vutbr.cz
5  * File: BidirectionallyUnNestNodeIterator.java
6  * Description: Node iterator which is gradually unnesting
7  */
8 
9 /**
10  * @file BidirectionallyUnNestNodeIterator.java
11  *
12  * @brief Node iterator which is gradually unnesting
13  */
14 
15 package cz.vutbr.fit.knot.annotations.fragmentUpdater.nodeIterators;
16 
18 import javax.xml.xpath.XPathExpression;
19 import javax.xml.xpath.XPathExpressionException;
20 import org.w3c.dom.Document;
21 import org.w3c.dom.Node;
22 
23 /**
24  * Node iterator which is gradually unnesting
25  *
26  * @brief Node iterator which is gradually unnesting
27  * @author Bc. Lukas Kubik
28  */
30 
31  /**
32  * Next node sides
33  *
34  * @brief Next node sides
35  */
36  protected enum flow {
37  LEFT, RIGHT
38  };
39 
40  /** Next node side. */
41  protected flow currentFlow;
42  protected Node nextNodeL, nextNodeR;
43  /**
44  * Loop end condition. It is activated when one of the loops steps out of
45  * the root node.
46  */
47  protected boolean leftEnd, rightEnd;
48  protected String sessionL;
49  protected String sessionR;
50 
51  /**
52  * Overriden initialization method.
53  *
54  * @param document document whose nodes will be iterated through
55  * @param expr expression according to which iterating will be provided
56  */
57  @Override
58  public void init(Document document, XPathExpression expr) throws XPathExpressionException {
59  this.timestamp = System.currentTimeMillis();
60  this.sessionL = "L" + this.timestamp;
61  this.sessionR = "R" + this.timestamp;
62  this.document = document;
63  this.nodeList = XPathHelper.evaluateXPath(document, expr);
64  this.currentNodeIndex = 0;
65  this.firstNode = true;
66  this.currentFlow = flow.RIGHT;
67  this.leftEnd = this.rightEnd = false;
68 
69  if (nodeList.getLength() == 0) {
70  nextNodeL = nextNodeR = null;
71  } else {
72  // First node which will be parsed
73  nextNodeL = nextNodeR = nodeList.item(currentNodeIndex);
74  }
75  }
76 
77  /**
78  * Overriden method for iterator's next node
79  *
80  * @return iterator's next node
81  */
82  @Override
83  public Node nextNode() {
84 
85  Node resultNode = null;
86 
87  if(firstNode){
88  firstNode = false;
91  // We can return both nodes because nextNodeL == nextNodeR
92  return nextNodeL;
93  }
94 
95  // Flow of right terminal nodes
96  if(currentFlow == flow.RIGHT && !rightEnd){
97  if (nextNodeR == null) {
98  rightEnd = true;
99  changeFlow();
100  return nextNode();
101  }
102 
103  // If the node is visited then we go to the right node or to parent's next node.
105  if(nextNodeR.getNextSibling() != null){
106  nextNodeR = nextNodeR.getNextSibling();
107  return nextNode();
108  }
109  else{
110  setVisited(nextNodeR.getParentNode(), currentFlow);
111  nextNodeR = nextNodeR.getParentNode();
112  return nextNode();
113  }
114  }
115  else{
116  if(nextNodeR.hasChildNodes()){
117  nextNodeR = nextNodeR.getFirstChild();
118  return nextNode();
119  }
120  else{
121  resultNode = nextNodeR;
123  }
124  }
125  }
126  // Flow of left terminal nodes
127  else if(!leftEnd){
128  if (nextNodeL == null) {
129  leftEnd = true;
130  changeFlow();
131  return nextNode();
132  }
133 
134  // If the node is visited then we go to the left node or to parent's previous node.
136  if(nextNodeL.getPreviousSibling() != null){
137  nextNodeL = nextNodeL.getPreviousSibling();
138  return nextNode();
139  }
140  else{
141  setVisited(nextNodeL.getParentNode(), currentFlow);
142  nextNodeL = nextNodeL.getParentNode();
143  return nextNode();
144  }
145  }
146  else{
147  if(nextNodeL.hasChildNodes()){
148  nextNodeL = nextNodeL.getLastChild();
149  return nextNode();
150  }
151  else{
152  resultNode = nextNodeL;
154  }
155  }
156  }
157  // No more nodes available
158  else{
159  return null;
160  }
161 
162  // If node is not empty or non text.
163  //if (resultNode.getNodeName().equals("#text") && !isWhitespaced(resultNode.getTextContent()))
164  if((resultNode.getNodeType() == Node.TEXT_NODE || resultNode.getNodeType() == Node.CDATA_SECTION_NODE)
165  && !isWhitespaced(resultNode.getNodeValue())){
166  if(!leftEnd && !rightEnd){
167  changeFlow();
168  }
169  return resultNode;
170  }
171 
172  return nextNode();
173 
174  }
175 
176  /**
177  * Is there any more node for comparing?
178  * @return True if yes, false if not
179  */
180  public boolean hasNext() {
181  if(leftEnd && rightEnd){
182  return false;
183  }
184  return true;
185  }
186 
187 
188  /**
189  * Changes current flow of the nodes.
190  */
191  protected void changeFlow() {
192  if(currentFlow == flow.RIGHT){
194  }
195  else{
197  }
198  }
199 
200  /**
201  * Sets node's "visited" flag
202  *
203  * @param node node which flag is to be set
204  * @param currentFlow next node side
205  */
206  private void setVisited(Node node, flow currentFlow) {
207  if (node == null) {
208  return;
209  }
210 
211  if(currentFlow == flow.RIGHT){
212  node.setUserData(this.sessionR, timestamp, null);
213  }
214  else{
215  node.setUserData(this.sessionL, timestamp, null);
216  }
217  }
218 
219  /**
220  * Getter of node's "visited" flag
221  *
222  * @param node node which flag is to be returned
223  * @param currentFlow next node side
224  * @return true if "visited" flag is set, false if isn't
225  */
226  private boolean isVisited(Node node, flow currentFlow) {
227  if (node == null) {
228  return true;
229  }
230 
231  Long visited = null;
232 
233  if(currentFlow == flow.RIGHT){
234  visited = (Long) node.getUserData(this.sessionR);
235  }
236  else{
237  visited = (Long) node.getUserData(this.sessionL);
238  }
239 
240  if (visited == null) {
241  return false;
242  }
243 
244  return (visited == timestamp);
245  }
246 
247  /**
248  * Overriden toString() method
249  *
250  * @return string representation of class
251  */
252  @Override
253  public String toString() {
254  return "BidirectionallyUnNest";
255  }
256 } // class BidirectionallyUnNestNodeIterator