From version < 13.1 >
edited by Marius Dumitru Florea
on 2019/12/11 15:55
To version < 16.1 >
edited by Marius Dumitru Florea
on 2019/12/12 14:59
< >
Change comment: There is no comment for this version

Summary

Details

ExtensionCode.ExtensionClass[0]
Description
... ... @@ -135,25 +135,17 @@
135 135  To compute the changes you need to use the ##XMLDiff## component.
136 136  
137 137  {{code language="java"}}
138 -public interface XMLDiff
139 -{
140 - /**
141 - * Computes the difference between two XML nodes and their descendants. When a text node, attribute, comment or any
142 - * value node type in general is modified we compute the difference at character level. Otherwise the difference is
143 - * expressed at node level, as if two lists of nodes are compared.Levenshtein distance
144 - * <p>
145 - * The result is a mapping between nodes from the left side and the patches that need to be applied to these nodes
146 - * in order for the left tree to become the right tree. If the root nodes of the left and right trees don't match
147 - * then this change is mapped to the {@code null} key.
148 - *
149 - * @param left the left side of the comparison
150 - * @param right the right side of the comparison
151 - * @param config the configuration
152 - * @return the differences between the two XML nodes
153 - * @throws DiffException if the difference can't be computed
154 - */
155 - Map<Node, Patch<?>> diff(Node left, Node right, XMLDiffConfiguration config) throws DiffException;
156 -}
138 [email protected]
139 +private XMLDiff xmlDiff;
140 +
141 [email protected]
142 +private XMLDiffConfiguration config;
143 +
144 +...
145 +
146 +Document left = parseXML("...");
147 +Document right = parseXML("...");
148 +Map<Node, Patch<?>> patches = this.xmlDiff.diff(left, right, this.config);
157 157  {{/code}}
158 158  
159 159  The default implementation uses the list diff API to compute the changes between child nodes, attributes and text content. The algorithm is quite simple:
... ... @@ -162,7 +162,8 @@
162 162  if leftNode and rightNode are "similar"
163 163   if leftNode has value (true for text, comment or attribute nodes)
164 164   if leftNode's value is different than rightNode's value
165 - compute the changes at character level (lists of characters)
157 + compute the changes using the splitter indicated in the configuration
158 + (character splitter is used for text nodes by default, but there is also a word splitter available)
166 166   else
167 167   if leftNode has attributes (true for elements)
168 168   compute the difference between attributes (added, removed, modified)
... ... @@ -179,31 +179,70 @@
179 179  very similar = similar and the percent of text changes (Levenshtein distance / max length) is less than 60%
180 180  {{/code}}
181 181  
175 +The similarity threshold (0.6 by default) can be changed from the configuration.
176 +
177 +As indicated in the algorithm described above, you can also change from the configuration the text splitter used for a specific node type. And, of course, you can implement your own splitter component.
178 +
179 +{{code language="java"}}
180 [email protected]
181 [email protected]("myCustomSplitter")
182 +private StringSplitter myCustomSplitter;
183 +
184 [email protected]
185 +private XMLDiffConfiguration config;
186 +
187 +...
188 +
189 +((DefaultXMLDiffConfiguration) this.config).setSplitterForNodeType(Node.TEXT_NODE, this.myCustomSplitter);
190 +{{/code}}
191 +
182 182  == Displaying the Changes ==
183 183  
184 -To compute and display the changes you can use the ##XMLDiffManager## component.
194 +The component responsible for computing and displaying the changes is ##XMLDiffManager##. There's no generic (default) implementation provided at the moment. The provided implementation is dedicated to displaying changes between HTML documents.
185 185  
186 186  {{code language="java"}}
187 -public interface XMLDiffManager
188 -{
189 - /**
190 - * Computes and marks the differences between two XML documents.
191 - *
192 - * @param left the left side of the comparison
193 - * @param right the right side of the comparison
194 - * @param config the configuration
195 - * @return the differences between the two XML documents
196 - * @throws DiffException if the difference can't be computed
197 - */
198 - String diff(String left, String right, XMLDiffConfiguration config) throws DiffException;
199 -}
197 +@Inject
198 +@Named("html/unified")
199 +private XMLDiffManager unifiedHTMLDiffManager;
200 +
201 +@Inject
202 [email protected]Named("html")
203 +private XMLDiffConfiguration config;
204 +
205 +...
206 +
207 +String previousHTML = "...";
208 +String nextHTML = "...";
209 +String diff = this.unifiedHTMLDiffManager.diff(previousHTML, nextHTML, this.config)
200 200  {{/code}}
201 201  
202 -=== HTML Visual Diff ===
212 +You can control from the configuration which ##XMLDiffFilter##s are applied on the XML documents before and after computing the changes. You can also implement your own filters, e.g. to remove irrelevant changes, or to ignore parts of the XML documents while computing the changes. The default configuration applies a filter to mark context (unmodified) nodes after the changes are computed.
203 203  
204 -The ##XMLDiffManager## has an implementation dedicated to computing a visual diff on HTML. Best is to use the provided script service:
214 +{{code language="java"}}
215 [email protected]
216 [email protected]("myCustomFilter")
217 +private XMLDiffFilter myCustomFilter;
205 205  
219 [email protected]
220 [email protected]("html")
221 +private XMLDiffConfiguration config;
222 +
223 +...
224 +
225 +this.config.getFilters().add(this.myCustomFilter);
226 +{{/code}}
227 +
228 +== Script Service ==
229 +
230 +Here's how you can compute and display the changes from a Velocity script:
231 +
206 206  {{code language="none"}}
233 +{{velocity}}
234 +{{html clean="false"}}
235 +#set ($discard = $xwiki.ssfx.use('uicomponents/viewers/diff.css', true))
236 +#set ($discard = $xwiki.jsfx.use('uicomponents/viewers/diff.js'))
237 +#set ($previousHTML = '<p>one two three</p>')
238 +#set ($nextHTML = '<p>one 2 three</p>')
207 207  <div class="html-diff">
208 208   #set ($htmlDiff = $services.diff.html.unified($previousHTML, $nextHTML))
209 209   #if ($htmlDiff == '')
... ... @@ -214,4 +214,19 @@
214 214   $htmlDiff
215 215   #end
216 216  </div>
249 +{{/html}}
250 +{{/velocity}}
217 217  {{/code}}
252 +
253 +You can configure the diff by passing a third argument:
254 +
255 +{{code language="none"}}
256 +#set ($config = $services.diff.html.defaultConfiguration)
257 +#set ($discard = $config.setSimilarityThreshold(0.6))
258 +#set ($discard = $config.addFilter('hintOfMyCustomFilter'))
259 +## Change the splitter used for text nodes from 'character' to 'word'.
260 +#set ($discard = $config.setSplitterForNodeType(3, 'word'))
261 +#set ($htmlDiff = $services.diff.html.unified($previousHTML, $nextHTML, $config))
262 +{{/code}}
263 +
264 +The default configuration applies a filter that embeds images into the HTML before computing the changes, in order to compare the image data and not the image location.

Get Connected