4A Server -  2.0
 All Classes Namespaces Files Functions Variables Enumerator
DocumentUpdateHelper.java
Go to the documentation of this file.
1 /*
2  * Project: Server for annotations sharing
3  * Author: Ing. Jaroslav Dytrych idytrych@fit.vutbr.cz
4  * File: DocumentUpdateHelper.java
5  * Description: Document update helper which contains methods necessary to provide modification process
6  */
7 
8 /**
9  * @file DocumentUpdateHelper.java
10  *
11  * @brief Document update helper which contains methods necessary to provide modification process
12  */
13 package cz.vutbr.fit.knot.annotations.document;
14 
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
22 import javax.xml.xpath.XPath;
23 import javax.xml.xpath.XPathConstants;
24 import javax.xml.xpath.XPathExpressionException;
25 import javax.xml.xpath.XPathFactory;
26 import org.w3c.dom.Document;
27 import org.w3c.dom.NamedNodeMap;
28 import org.w3c.dom.Node;
29 import org.w3c.dom.NodeList;
30 
31 /**
32  * Document update helper class which contains methods necessary to provide modification process
33  *
34  *
35  * @author Jan Paulovcak (xpaulo00 at stud.fit.vutbr.cz)
36  * @brief Document update Helper
37  */
38 public class DocumentUpdateHelper {
39 
40  /**
41  * Search for a node with exact Xpath within a given document
42  *
43  * @param doc Document in which method will search for a node
44  * @param path Xpath of node
45  * @return Returns node on success, null otherwise
46  *
47  */
48  public static Node getDocumentNode(Document doc, String path){
49  //Evaluate XPath against Document itself
50  XPath xPath = XPathFactory.newInstance().newXPath();
51  NodeList nodes;
52 
53  try {
54  nodes = (NodeList)xPath.evaluate(path, doc, XPathConstants.NODESET);
55  } catch (XPathExpressionException ex) {
56  Logger.getLogger(DocumentUpdateHelper.class.getName()).log(Level.SEVERE, null, ex);
57  return null;
58  }
59 
60  return nodes.item(0);
61  }
62 
63  /**
64  * Creates XPath for node that will be used in reversed modifications
65  *
66  * It uses name of child node as a stopper while counting number of nodes with the same name
67  *
68  * @param xpath XPath of source node
69  * @param sourceNode Node used in modification
70  * @param childNodeName Node name of child node
71  * @param mode Mode of text modification
72  */
73  public static String getNodePathForReversed(String xpath, Node sourceNode, String childNodeName, int mode){
74 
75  StringBuilder sb = new StringBuilder(xpath.substring(0, xpath.lastIndexOf("/")+1));
76 
77  Node child = sourceNode.getParentNode().getFirstChild();
78 
79  int counter = 1;
80 
81  while(child != null){
82  /* In insertBefore or replace mode counting has to be done just to node, before whom we inserted */
83  if((child.equals(sourceNode) && mode == Constants.TEXT_MOD_INS_BEFORE) || (child.equals(sourceNode) && mode == Constants.TEXT_MOD_REPLACE)){
84  break;
85  }
86  /* In case of insertAfter, counting has to be stop exactly one place after source node */
87  if(child.equals(sourceNode) && mode == Constants.TEXT_MOD_INS_AFTER){
88  if(child.getNodeName().equals(childNodeName)){
89  counter++;
90  }
91  break;
92  }
93 
94  if(child.getNodeName().equals(childNodeName)){
95  counter++;
96  }
97  child = child.getNextSibling();
98  }
99 
100  if(childNodeName.equals("#text")){
101  sb.append("text()[").append(counter).append("]");
102  }
103  else{
104  sb.append(childNodeName).append("[").append(counter).append("]");
105  }
106 
107  return sb.toString();
108  }
109 
110  /**
111  * Converts node into string form
112  *
113  * @param root Node to convert
114  * @return Returns node in string form
115  *
116  */
117  public static String nodeToString(Node root){
118 
119  String rootName = root.getNodeName().toLowerCase();
120  StringBuilder sb = new StringBuilder();
121 
122  if(root.getNodeType() != Node.TEXT_NODE){
123  if(root.getNodeName().equalsIgnoreCase("br")){
124  return "<br />";
125  }
126  else if(root.getNodeName().equalsIgnoreCase("hr")){
127  return "<hr />";
128  }
129 
130  if(root.getAttributes() != null && !rootName.equalsIgnoreCase("head"))
131  sb.append("<").append(rootName)
132  .append(nodeAttributesToString(root.getAttributes())).append(">");
133 
134  else{
135  sb.append("<").append(rootName).append(">");
136  }
137 
138  NodeList nl = root.getChildNodes();
139  for(int i = 0; i < nl.getLength(); i++){
140  Node n = nl.item(i);
141  if(n.getNodeType() == Node.TEXT_NODE){
142  sb.append(n.getNodeValue());
143  }
144  else{
145  sb.append(nodeToString(n));
146  }
147  }
148  sb.append("</").append(rootName).append(">");
149  }
150  else{
151  sb.append(root.getNodeValue());
152  }
153 
154  return sb.toString();
155  }
156 
157  /**
158  * Converts all node's attributes into string form
159  *
160  * @param map Map with attributes
161  * @return Returns attributes in string form
162  *
163  */
164  public static String nodeAttributesToString(NamedNodeMap map){
165  StringBuilder sb = new StringBuilder();
166 
167  for(int i = 0; i < map.getLength(); i++){
168  Node n = map.item(i);
169  sb.append(" ").append(n.getNodeName()).append("=\"").append(n.getNodeValue()).append("\"");
170  }
171 
172  return sb.toString();
173  }
174 
175 
176  /**
177  * Sorts list of modifications based upon two criteriums
178  * First is to sort XPaths alphabetically, in descending order
179  * Second is applied only in case that XPaths are the same, then the modification
180  * with higher priority will be first
181  * Priority levels of modifications are set within Constants module
182  *
183  * @param list List of modifications
184  */
185  public static void sortModifications(ArrayList<TextModification> list){
186 
187  Collections.sort(list, new Comparator<TextModification>() {
188 
189  @Override
190  public int compare(TextModification mod1, TextModification mod2){
191 
192  int pathComp = (mod2.getPath() + "z").compareTo(mod1.getPath() + "z");
193  return pathComp == 0 ? mod2.getMode() - mod1.getMode() : pathComp;
194 
195  }
196  });
197  }
198 
199  /**
200  * Removes unnecessary elements from array list
201  *
202  * @param list Array list of elements
203  * @param start Start position
204  * @param end End position
205  */
206  public static void removeListElements(ArrayList<TextModification> list, int start, int end){
207  ArrayList<TextModification> group1 = new ArrayList<TextModification>(list.subList(0, start));
208  ArrayList<TextModification> group2 = new ArrayList<TextModification>(list.subList(end, list.size()));
209  list.clear();
210  list.addAll(group1);
211  list.addAll(group2);
212  }
213 
214 } // public class DocumentUpdateHelper
static String getNodePathForReversed(String xpath, Node sourceNode, String childNodeName, int mode)
Class representing modification of annotated document text.
static void sortModifications(ArrayList< TextModification > list)
static void removeListElements(ArrayList< TextModification > list, int start, int end)