Changes for page Diff Module
Last modified by Marius Dumitru Florea on 2020/06/19 14:42
edited by Marius Dumitru Florea
on 2019/12/11 15:55
on 2019/12/11 15:55
edited by Marius Dumitru Florea
on 2019/12/12 14:59
on 2019/12/12 14:59
Change comment:
There is no comment for this version
Summary
-
Objects (1 modified, 0 added, 0 removed)
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 comput eand display the changesyou can usethe##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 XMLDiffManager188 - {189 - /**190 - * Computes and marks the differences between two XML documents.191 - *192 - *@paramleft the left side of the comparison193 - * @param righttherightsideofthecomparison194 - * @param config the configuration195 - * @return the differences between the two XML documents196 - * @throws DiffException if the difference can't be computed197 - */198 - diff(String left, String right, XMLDiffConfigurationconfig)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 - ===HTMLVisualDiff===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.