Skip to main content
Skip table of contents

Detecting and Handling Moves

Introduction

This document describes the concepts behind the detecting and handling of moves. The sample resources, including a description on how to run it can be found here.

This "how to" document discusses how you can detect a move rather than a delete and an add

Handling Moves

What are Moves

At its core, a move is matching an add and delete of the element with same name content.

Take the following 2 files:

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<topic>
    <title>A Simple Move</title>
    <body>
        <section>
            <p>Start</p>
            <p>One</p>
        </section>
        <section>
            <p>Two</p>
            <p>Finish</p>
        </section>
    </body>
</topic>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<topic>
    <title>A Simple Move</title>
    <body>
        <section>
            <p>Start</p>
        </section>
        <section>
            <p>One</p>
            <p>Two</p>
            <p>Finish</p>
        </section>
    </body>
</topic>

Running a plain comparison with XML Compare would yield the following result:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<topic xmlns="http://my.default.org"
    xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute"
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" deltaxml:deltaV2="A!=B"
    deltaxml:content-type="full-context" deltaxml:version="2.0">
    <title deltaxml:deltaV2="A=B">A Simple Move</title>
    <body deltaxml:deltaV2="A!=B">
        <section deltaxml:deltaV2="A!=B">
            <p deltaxml:deltaV2="A=B">Start</p>
            <p deltaxml:deltaV2="A">One</p>
        </section>
        <section deltaxml:deltaV2="A!=B">
            <p deltaxml:deltaV2="B">One</p>
            <p deltaxml:deltaV2="A=B">Two</p>
            <p deltaxml:deltaV2="A=B">Finish</p>
        </section>
    </body>
</topic>

It can be seen that the second <p> element in the first <section> with the text "One" is deleted and the same content is added in the second <section>. Therefore, it could be argued that the <p> element has moved from the first <section> to the second. The next part of this documentation will describe how XML Compares move handling affects this result and represents moves in a more comprehensive manner than simple addition and deletions.

What does Move Processing do when switched on?

Once move handling is enabled the following result will be produced from the same inputs as above:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<topic xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute"
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" deltaxml:deltaV2="A!=B"
    deltaxml:content-type="full-context" deltaxml:version="2.0">
    <title deltaxml:deltaV2="A=B">A Simple Move</title>
    <body deltaxml:deltaV2="A!=B">
        <section deltaxml:deltaV2="A!=B">
            <p deltaxml:deltaV2="A=B">Start</p>
            <p deltaxml:deltaV2="A" deltaxml:move-id="d379e19">One</p>
        </section>
        <section deltaxml:deltaV2="A!=B">
            <p deltaxml:move-idref="d379e19" deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A=B">One</p>
            <p deltaxml:deltaV2="A=B">Two</p>
            <p deltaxml:deltaV2="A=B">Finish</p>
        </section>
    </body>
</topic>

It can be seen that the delta with moves now shows 2 things:

  1. The Move has been identified using a pair of attributes

    1. The Move Source, the deleted <p> element from input A, is identified using a @deltaxml:move-id and the Move Target, the inserted <p> element from input B, is identified using a @deltaxml:move-idref which has the same value as the @deltaxml:move-id. We call this a Move Pair.

  2. The Move Target has been updated to show the differences between the deleted and inserted elements from the Move Pair. The Move Target shows the Aligned Moved Pair.

Moves Delta Syntax

In order to make what happens in a move more explicit and easier to process we decided to make some additions to the deltaV2 syntax, by adding “Moves Delta”. The aim of the deltaV2 syntax is to be able to extract the original inputs from a comparison result, thus the Move Delta syntax has been added as an extension of the standard deltaV2 syntax to aid in readability and processing of a final deltaV2 results with moves.
See the example below where p elements are moved inside an ordered list element ol, with additional modifications to the text in some of the elements:

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <title>A Simple Move</title>
    <body>
        <section>
            <title>A list of paras</title>
            <p>Start</p>
            <p>One</p>
            <p>Two</p>
            <p>Finish</p>
        </section>
    </body>
</root>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <title>A Simple Move</title>
    <body>
        <section>
            <title>A list of paras</title>
            <ol>
                <li><p>Start Here</p></li>
                <li><p>One 1</p></li>
                <li><p>Two 2 </p></li>
                <li><p>Finish Here</p></li>
            </ol>
        </section>
    </body>
</root>

With Moves processing the output will be as follows:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1" 
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute" 
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" 
    deltaxml:deltaV2="A!=B" deltaxml:content-type="full-context" deltaxml:version="2.0">
    <title deltaxml:deltaV2="A=B">A Simple Move</title>
    <body deltaxml:deltaV2="A!=B">
        <section deltaxml:deltaV2="A!=B">
            <title deltaxml:deltaV2="A=B">A list of paras</title>
            <p deltaxml:deltaV2="A" deltaxml:move-id="d379e19">Start</p>
            <p deltaxml:deltaV2="A" deltaxml:move-id="d379e23">One</p>
            <p deltaxml:deltaV2="A" deltaxml:move-id="d379e27">Two</p>
            <p deltaxml:deltaV2="A" deltaxml:move-id="d379e31">Finish</p>
            <ol deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A!=B">
                <li deltaxml:moveDeltaV2="A!=B">
                    <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e19">
                        Start
                        <deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="B"> Here</deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                    </p>
                </li>
                <li deltaxml:moveDeltaV2="A!=B">
                    <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e23">
                        One
                        <deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="B"> 1</deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                    </p>
                </li>
                <li deltaxml:moveDeltaV2="A!=B">
                    <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e27">
                        Two<deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="B"> 2 </deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                    </p>
                </li>
                <li deltaxml:moveDeltaV2="A!=B">
                    <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e31">
                        Finish<deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="B"> Here</deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                    </p>
                </li>
            </ol>
        </section>
    </body>
</root>

Notice that the @deltaxml:deltaV2 on the inserted ol element is @deltaxml:deltaV2="B" not @deltaxml:deltaV2="A!=B", thus it can be seen that it is an insert. In addition to the @deltaxml:deltaV2="B", it now has a @deltaxml:moveDeltaV2="A!=B" to show that it is the “insertion point” of a move. The @deltaxml:moveDeltaV2s then shows how the Move Source aligns with the Move Target. Where the text has been partially modified see there is now deltaxml:movedTextGroup and deltaxml:movedText, the Move Delta equivalent of deltaxml:textGroup and deltaxml:text.

The Move Deltas can be used to extract the A or B correctly from a Move Delta. In simple terms consider the following:

  • If something is marked with a @deltaxml:deltaV2="B" and has a @deltaxml:moveDeltaV2="A=B" or @deltaxml:moveDeltaV2="A!=B", extract the B by throwing away everything which has a @deltaxml:moveDeltaV2="A" and replacing elements like deltaxml:movedTextGroup with just the B contents.

  • When extracting an A simply ignore the Move Target as one would normally ignore elements with a @deltaxml:deltaV2="B", and there is no additional Move Delta processing to do as the Move Source provides the original location.

Previous Move Handling with Keys

For move processing in XML Compare 14.3.1 and before, each element that could potentially be moved required a unique identifier. The identifier was to be specified by the User using an XPath. We say the User therefore specified a set of Moveable elements by providing a XPath.

The Move Pair was found by looking for a deleted element from A with the same identifier as an inserted element from B. If the identifier was not unique within the whole file then the Move was not detected. If the identifier was on an element which was aligned @deltaxml:deltaV2="A=B" or @deltaxml:deltaV2="A!=B" then no Move Processing happened because the element has not moved.

This original approach had its strengths in simplicity and relative efficiency, however also had weaknesses in having to specify unique identifiers in advance, keys being brittle, keys needing to be unique across a whole file, and moves not being detected when an element was not itself an insert or delete, but a descendant within a wholly added or deleted unaligned subtree e.g. wrapping an sequence of paragraphs inside a list.

The Move to Candidates

Considering the weaknesses of the original moves implementation, the following questions were asked: What if the elements which we want to process as Moves don’t have any obvious/easy unique identifiers to add? Or if the elements are known to be within an added or deleted subtree following refactoring, for example a sequence of paras being moved within an ordered list?

A new way of handling moves was developed to combat these and the weaknesses of Move Keys, replacing the Move Keys with MoveCandidates. Like Move Keys this relies on the User specifying an Xpath to indicate what elements are Moveables. However unlike Move Keys the values it provides do not have to be unique across the input, they can be things like element names. Elements with the same value for this Xpath belong to the same “Move Class” and processing will attempt to detect moves between Move Candidates with the same Move Class.

See our Bitbucket Sample here.

Moves configuration

For the full Java API see our API docs here, and see the DCP Schema Guide for more information on configuration using a DCP.

Enable moves handling

The previous move handling with keys has been removed from the API.

Previously Moves required the use of keys, however an entire overhaul has been implemented; this feature has been removed in place of the improved move algorithms making use of move candidates. Below is how moves was previously implemented in the java api, making use of the resultReadability options and setting a moveAtributeXpath:

CODE
import com.deltaxml.cores9api.config.ResultReadabilityOptions;
ResultReadabilityOptions options= new ResultReadabilityOptions();
options.setDetectMoves(true);
options.setMoveAttributeXpath("@id");
DocumentComparator comp= new DocumentComparator();
comp.setResultReadabilityOptions(options);

To make use of the new move handling with improved results see how to implement using a DCP in the Bitbucket sample here or in Java with the code sample below:

CODE
List<MoveCandidate> moveCandidates = new ArrayList<>();​

MoveCandidate moveCandidate = new MoveCandidate("p", "'p’”);​

moveCandidates.add(moveCandidate);​

final MoveDetectionConfig config = new MoveDetectionConfig(moveCandidates);​

DocumentComparator dc= new DocumentComparator();​

dc.setMoveDetectionConfig(config);

Note, that Move handling is not enabled by default, therefore ensure that moves has been set up correctly to process results as desired.

Move Detection Algorithms

Unrestricted

In this case, the algorithm looks for Move Candidates as added or deleted Moveables which are anywhere within added or deleted subtrees regardless of whether it has a Moveable ancestor which is itself within that added or deleted subtree. Unrestricted is the default algorithm for move handling in the Document Comparator as it provides the most freedom with moves for user comparisons, allowing for moves to be found across the whole document rather than within the limits scope of the restricted algorithm.

Below shows an example in which some Moveables are within other Moveables which have been added, deleted or themselves moved. The Restricted algorithm does not spot these types of Moves, however they are handled by the Unrestricted Algorithm. The example shows moves of both <p> elements across the <li> elements, and of the <li> elements themselves.

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ol>
        <li>
            <ballast>One 1 Un Eins Uno</ballast>
            <p>Hickory dickory dock</p>
            <p>A mouse ran up the clock</p>
            <p>Le horloge struck one</p>
        </li>
        <li>
            <ballast>Four 4 Quatre Vier Cuatro</ballast>
            <p>The mus walked down.</p>
        </li>
        <li>
            <ballast>Five 5 Cinq Funf Cinco</ballast>
            <p>Ye phone chimed two</p>
        </li>
        <li>
            <ballast>Six 6 Sechs Seis</ballast>
            <p>And he jumped and flew.</p>
        </li>
    </ol>
</root>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ol>
        <li>
            <ballast>Six 6 Sechs Seis</ballast>
            <p>The mus walked down.</p>
            <p>Ye phone chimed two</p>
            <p>And he jumped and flew.</p>
        </li>
        <li>
            <ballast>Two 2 Deux Zwei Dos</ballast>
            <p>A mouse ran up the clock</p>
        </li>
        <li>
            <ballast>Three 3 Trois Drei Tres</ballast>
            <p>Le horloge struck one</p>
        </li>
        <li>
            <ballast>One 1 Un Eins Uno</ballast>
            <p>Hickory dickory dock</p>
        </li>
    </ol>
</root>

The result will be as follows:

Screenshot 2024-05-08 at 13.50.42-20240508-125950.png

The use of the Unrestricted algorithm allows elements to be considered moves anywhere in the file, thus it can be seen the <p> elements have been tracked moving across <li> elements via the red lines in the pictured result above, and the moves of the <li> elements are indicated with blue lines. This example introduces an addition to the Moves Delta syntax with deltaxml:move-correspondance-idRef, this new Move Delta has been added to indicate additional copies of the A source within Move Target, in this case additional copies of <p> elements containing A Mouse ran up the clock and Le horloge struck one from A in the Move target of <li> (see the green dashed line in the pictured example).

Restricted

In this case the algorithm looks for Move Candidates as added or deleted Moveables which are the roots of added or deleted subtrees. That is they have a @deltaxml:deltaV2 of “A” or “B” directly on them and their parents have a deltaxml:deltaV2="A!=B".

This example shows moves of the <p> elements across the <li> elements, which are valid moves within the Restricted algorithm.

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ol>
        <li>
            <ballast>One 1 Un Eins Uno</ballast>
            <p>Hickory dickory dock</p>
        </li>
        <li>
            <ballast>Two 2 Deux Zwei Dos</ballast>
            <p>A mouse ran up the clock</p>
        </li>
        <li>
            <ballast>Three 3 Trois Drei Tres</ballast>
            <p>Le horloge struck one</p>
        </li>
        <li>
            <ballast>Four 4 Quatre Vier Cuatro</ballast>
            <p>The mus walked down.</p>
        </li>
        <li>
            <ballast>Five 5 Cinq Funf Cinco</ballast>
            <p>Ye phone chimed two</p>
        </li>
        <li>
            <ballast>Six 6 Sechs Seis</ballast>
            <p>And he jumped and flew.</p>
        </li>
    </ol>
</root>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ol>
        <li>
            <ballast>One 1 Un Eins Uno</ballast>
            <p>Hickory dickory dock</p>
        </li>
        <li>
            <ballast>Two 2 Deux Zwei Dos</ballast>
            <p>The mus walked down.</p>
        </li>
        <li>
            <ballast>Three 3 Trois Drei Tres</ballast>
            <p>Ye phone chimed two</p>
        </li>
        <li>
            <ballast>Four 4 Quatre Vier Cuatro</ballast>
            <p>A mouse ran up the clock</p>
        </li>
        <li>
            <ballast>Five 5 Cinq Funf Cinco</ballast>
            <p>Le horloge struck one</p>
        </li>
        <li>
            <ballast>Six 6 Sechs Seis</ballast>
            <p>And he jumped and flew.</p>
        </li>
    </ol>
</root>

The result will be as follows:

Screenshot 2024-05-08 at 14.00.36-20240508-130207.png

In the result it can be seen that Moves are found on the <p> elements which are considered as root of added or deleted subtrees i.e. each <p> considered as a move has a @deltaxml:deltaV2 of “A” or “B” directly and is within the <li> element which has a @deltaxml:deltaV2="A!=B".

Move Candidates

moveCandidates allow users to specify which elements should be considered moveable.  By providing an element XPath and optionally providing a class XPath, elements that match the element XPath and are within the same class XPath will be compared with each other to find a matching pair that constitutes a move.

moveCandidate() takes 2 arguments, the first being the elemXPath which declares which elements are moveable e.g. “p” will define <p> elements (with no namespace), whilst the second argument classXPath can optionally be defined and it allows for specifying groupings for moveable elements (only elements within the same group i.e class can be matched with each other)

Setting Move Candidates in the Java API

To add move candidates using the Java API see the code below. Individual move candidates are added to the moveCandidate list which can then be provided to the MoveDetectionConfig. Note, if the moveClass is empty as seen on line 2 the classXpath will take the same Xpath as the elemXpath therefore in this case new MoveCandidate("p", "");​ is functionally equivalent to new MoveCandidate("p", "'p'");. Once all desired setting are provided to the MoveDetectionConfig, it can be provided to the Document Comparator.

CODE
List<MoveCandidate> moveCandidates = new ArrayList<>();
MoveCandidate moveCandidate = new MoveCandidate("p", "");
moveCandidates.add(moveCandidate);
MoveCandidate moveCandidate2 = new MoveCandidate("pie:li", "'li'");
moveCandidates.add(moveCandidate2);

MoveDetectionConfig moveDetectionConfig = new MoveDetectionConfig(moveCandidates);

Enabling moves on all elements

In order to enable moves on all elements, consider using the * Xpath which can be implemented with on of the following lines:

CODE
MoveCandidate moveCandidate = new MoveCandidate("*", "");

See an example of this with the DCP in use in our Bitbucket Sample.

Show Move Source

A feature requested by our users, setShowMoveSource allows for users to choose how their moves are displayed in the final result. When enabling showMoveSource the user will see both the move source and the move target of each move. When disabled the Move Source will be omitted from the result and only the move target will be shown. This feature is enable by default, see the example below for how to enable and the change when showMoveSource is disabled. See in the code sample below after MoveDetectionConfig has been created the setShowMoveSource function can be used to enable or disable the feature, or to see our Bitbucket Sample for how to set this feature in the DCP .

CODE
    final MoveDetectionConfig moveDetectionConfig = new MoveDetectionConfig(moveCandidates);
    moveDetectionConfig.setShowMoveSource(false);

Consider the following 2 files:

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <div>
        <p>Open the packet and place it in a jug</p>
        <p>Quick brown foxes jump</p>
    </div>
</root>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <div>
        <ol>
            <li>
                <p>Open the packet and place it in a big jug</p>
                <p>Quick red foxes leap</p>
            </li>
        </ol>
    </div>
</root>

Running a comparison with XML Compare, moves enable, and show Move source enable (as it is by default) would yield the following result:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute"
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" deltaxml:deltaV2="A!=B"
    deltaxml:content-type="full-context" deltaxml:version="2.0">
    <div deltaxml:deltaV2="A!=B">
        <p deltaxml:deltaV2="A" deltaxml:move-id="d379e8">Open the packet and place it in a jug</p>
        <p deltaxml:deltaV2="A" deltaxml:move-id="d379e12">Quick brown foxes jump</p>
        <ol deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A!=B">
            <li deltaxml:moveDeltaV2="A!=B">
                <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e8">
                    Open the packet and place it in a 
                    <deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                        <deltaxml:movedText deltaxml:moveDeltaV2="B">big</deltaxml:movedText>
                    </deltaxml:movedTextGroup>
                    jug
                </p>
                <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e12">
                    Quick
                        <deltaxml:movedTextGroup deltaxml:moveDeltaV2="A!=B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="A">brown foxes jump</deltaxml:movedText>
                            <deltaxml:movedText deltaxml:moveDeltaV2="B">red foxes leap</deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                </p>
            </li>
        </ol>
    </div>
</root>

However, we have provided the option to remove the move source, which would yield the following result:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute"
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" deltaxml:deltaV2="A!=B"
    deltaxml:content-type="full-context" deltaxml:version="2.0">
    <div deltaxml:deltaV2="A!=B">
        <ol deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A!=B">
            <li deltaxml:moveDeltaV2="A!=B">
                <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e8">
                    Open the packet and place it in a 
                    <deltaxml:movedTextGroup deltaxml:moveDeltaV2="B">
                        <deltaxml:movedText deltaxml:moveDeltaV2="B">big</deltaxml:movedText>
                    </deltaxml:movedTextGroup>
                    jug
                </p>
                <p deltaxml:moveDeltaV2="A!=B" deltaxml:move-idref="d379e12">Quick
                        <deltaxml:movedTextGroup deltaxml:moveDeltaV2="A!=B">
                            <deltaxml:movedText deltaxml:moveDeltaV2="A">brown foxes jump</deltaxml:movedText>
                            <deltaxml:movedText deltaxml:moveDeltaV2="B">red foxes leap</deltaxml:movedText>
                        </deltaxml:movedTextGroup>
                </p>
            </li>
        </ol>
    </div>
</root>

Notice the difference between the two result, with the initial result including the Move Source with attributes @deltaxml:deltaV2="A" and @deltaxml:move-id, and the second result excluding those elements and only the Move Target is kept with all the all the information about the change provided through the new Move Delta Syntax.

Setting namespaces

If the inputs have namespaces declared and used in any elements that the user wants to detect moves on, then either a default namespace or user namespaces (or both) must be set. If the inputs do not contain any namespaces then neither default nor user namespaces are required as all move Candidates will be recognised for moves.

Consider the following configuration which shows examples of how to set both the default namespace and user namespaces. In this example, the move candidates are <p> and <li> elements, with the <li> elements having specific names spaces, and the user NameSpaces are additionally set as 'pie' and 'instructions'. Note the the default namespace in this case would be http://my.default.org, however setting of a default namespace has been commented out for the purposes of this example.

CODE
List<MoveCandidate> moveCandidates = new ArrayList<>();
moveCandidates.add(new MoveCandidate("p", ""));
moveCandidates.add(new MoveCandidate("pie:li", ""));
moveCandidates.add(new MoveCandidate("instructions:li", ""));
final MoveDetectionConfig moveDetectionConfig = new MoveDetectionConfig(moveCandidates);
//moveDetectionConfig.setDefaultNamespace("http://my.default.org");
Map<String, String> userNamespaces = new HashMap<>();
userNamespaces.put("pie", "http://example.com");
userNamespaces.put("instructions", "http://pie.com");
moveDetectionConfig.setUserNamespaces(userNamespaces);

Now consider the following inputs in conjunction with this configuration:

A

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root
    xmlns="http://my.default.org"
    xmlns:document="http://documentation.com"
    xmlns:pie="http://example.com"
    xmlns:instructions="http://pie.com">
    <head>
        <ul>
            <pie:li>One</pie:li>
            <pie:li>Two</pie:li>
            <li>Three</li>
            <instructions:li>Four</instructions:li>
        </ul>
    </head>
    <body>
        <div> 
            <p>Five</p>
            <p>Six</p>
            <p>Seven</p>
            <title>Place the pie in the oven</title>
        </div>
    </body>
</root>

B

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root 
    xmlns="http://my.default.org"
    xmlns:document="http://documentation.com"
    xmlns:pie="http://example.com" 
    xmlns:instructions="http://pie.com">
    <head>
        <ul>
            <pie:li>One</pie:li>
            <li>Three</li>
            <p>Five</p>
        </ul>
    </head>
    <body>
        <div> 
            <p>Six</p>
            <instructions:li>Four</instructions:li>
            <p>Seven</p>
            <title>Eight</title>
        </div>
        <pie:li>Two</pie:li>
    </body>
</root>

The result is as follows:

CODE
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://my.default.org" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
    xmlns:dxx="http://www.deltaxml.com/ns/xml-namespaced-attribute"
    xmlns:dxa="http://www.deltaxml.com/ns/non-namespaced-attribute" deltaxml:deltaV2="A!=B"
    deltaxml:content-type="full-context" deltaxml:version="2.0">
    <head deltaxml:deltaV2="A!=B">
        <ul deltaxml:deltaV2="A!=B">
            <pie:li xmlns:pie="http://example.com" deltaxml:deltaV2="A=B">One</pie:li>
            <pie:li xmlns:pie="http://example.com" deltaxml:deltaV2="A" deltaxml:move-id="d385e15">Two</pie:li>
            <li deltaxml:deltaV2="A=B">Three</li>
            <instructions:li xmlns:instructions="http://pie.com" deltaxml:deltaV2="A" deltaxml:move-id="d385e23">Four</instructions:li>
            <p deltaxml:deltaV2="B">Five</p>
        </ul>
    </head>
    <body deltaxml:deltaV2="A!=B">
        <div deltaxml:deltaV2="A!=B">
            <p deltaxml:deltaV2="A">Five</p>
            <p deltaxml:deltaV2="A=B">Six</p>
            <instructions:li xmlns:instructions="http://pie.com" deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A=B" deltaxml:move-idref="d385e23">Four</instructions:li>
            <p deltaxml:deltaV2="A=B">Seven</p>
            <title deltaxml:deltaV2="A">Place the pie in the oven</title>
            <title deltaxml:deltaV2="B">Eight</title>
        </div>
        <pie:li xmlns:pie="http://example.com" deltaxml:deltaV2="B" deltaxml:moveDeltaV2="A=B" deltaxml:move-idref="d385e15">Two</pie:li>
    </body>
</root>

In this example, it can be seen that the only elements with the ‘pie’ and ‘instructions' namespaces have been considered as moved elements i.e. <instructions:li> with text content ‘Four’, and <pie:li> with text content ‘Two’. Regardless of the <p> element with text content ‘Five’ being a moved element it is not considered as a move candidate because it is within the default namespace of http://my.default.org which was not set for this comparison.

Restrictions

Due to the scope and complexity of considering moves within comparison, there are currently some limitations:

  • Formatting elements are not considered as moves

  • Tables have restrictions on moves, primarily columns not being considered for moves.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.