Accepting Revisions in Open XML Word-Processing Documents

Summary:   Revision tracking markup in Open XML word-processing documents is one of the more complex areas of the standard. Accepting tracked revisions makes processing of text in word-processing documents simpler. Learn about the Open XML markup that deals with revision tracking, and how to programmatically accept tracked revisions using the Open XML Format SDK 2.0. (19 printed pages)

Eric White, Microsoft Corporation

December 2009

Applies to:   Microsoft Office Word 2007

Contents

  • Overview

  • Understanding the Difference Between Collapsing and Removing

  • Removing Elements

  • Collapsing Elements

  • Table Cell Deletion (cellDel Element)

  • Vertically Merged/Split Table Cells (cellMerge Element)

  • Content Control Deletion Start and End (customXmlDelRangeStart Element and customXmlDelRangeEnd Element)

  • Deleted Math Control Character (del Element)

  • Deleted Paragraph (del Element)

  • Deleted Table Row (del Element)

  • Move Source Paragraph (moveFrom Element)

  • Move Source Location Container—Start and End (moveFromRangeStart Element and moveFromRangeEnd Element)

  • Conclusion

  • Additional Resources

Overview

Tracking revisions in Open XML documents is one of the most important features of the document format. It is very useful to programmatically accept revisions using the Open XML SDK. In one scenario, you may have a SharePoint document library that contains documents designed and written for distribution outside your company. You want to ensure that there are no tracked revisions in any document in the document library. You could implement code to accept revisions as the document is saved into the document library. Another scenario: many kinds of complex text processing operations are made much simpler if we first accept tracked revisions. For instance, it is easier to write a high-fidelity conversion of Open XML to XHTML if you first accept all revisions, and then perform the appropriate transforms. These are just some the interesting scenarios. There are many more.

This article examines the semantics of transforming an Open XML word-processing document that contains tracked revisions to one that contains no revisions. I implemented these algorithms in a class, RevisionAccepter, which is part of the PowerTools for Open XML project, an open source project on CodePlex.

The use of RevisionAccepter.AcceptRevisions is simple. You call a static method in the RevisionAccepter class by using an open WordprocessingDocument object. Upon return of the method, the document contains no tracked revisions.

using (WordprocessingDocument doc =
    WordprocessingDocument.Open("DocumentWithRevisions.docx", true))
{
    RevisionAccepter.AcceptRevisions(doc);
}

The RevisionAccepter class uses a recursive approach to XML transformation using LINQ to XML. For details about that code, see the following blog post: Recursive Pure Functional Transformations of XML.

NoteNote

The PowerTools for Open XML are licensed under the Microsoft Public License (Ms-PL) license, which gives you wide latitude in how you use the code, so download the RevisionAccepter class and try it out. To download it, see PowerTools for OpenXml 1.1.1.

The Open XML markup for revision tracking is extensive—there are more than 40 elements that we must process when accepting tracked revisions. Although some are simple to process, other elements are more involved.

There are more than 20 elements that must be removed (together with their descendants) from the XML tree. There are several elements that must be collapsed—the element must be replaced with its descendant elements.

Understanding the Difference Between Collapsing and Removing

It is useful to define what collapsing an element means and how collapsing is related to removing an element. The processing of an inserted paragraph requires collapsing the w:ins element. To show exactly what collapsing means, consider the following markup that shows that a paragraph was inserted while revisions were being tracked. The inserted paragraph is preceded and followed with empty paragraphs.

<w:p/>
<w:ins w:id="16"w:author="Eric White"w:date="2009-08-29T06:47:00Z">
  <w:p>
    <w:r>
      <w:t>This is another inserted paragraph.</w:t>
    </w:r>
  </w:p>
</w:ins>
<w:p/>

Collapsing the w:ins element means that we remove the w:ins element, and promote its child element or elements to the level of the w:ins element. The resulting markup after accepting revisions looks as follows:

<w:p/>
<w:p>
  <w:r>
    <w:t>This is another inserted paragraph.</w:t>
  </w:r>
</w:p>
<w:p/>

In contrast, removing an element eliminates that element and all descendants from the resulting XML tree. The following is markup for a deleted paragraph. To accept this tracked revision, the w:del element and its descendants are removed.

<w:p/>
<w:del w:id="2"w:author="Eric White"w:date="2009-09-11T07:53:00Z">
  <w:p>
    <w:r>
      <w:delText>You can create pictures, charts, or diagrams.</w:delText>
    </w:r>
  </w:p>
</w:del>
<w:p/>

The resulting markup after accepting revisions looks as follows:

<w:p/>
<w:p/>

Note that collapsing an element that has no descendant elements effectively is the same as removing that element. In some situations, you must collapse some elements, whereas you must remove other elements with the same tag. For better performance and simpler code, in those situations, I collapse all elements, which removes those elements that have no descendants.

Removing Elements

By far, when accepting revisions, the most common operation is to remove elements. You must remove the following elements (and descendants if any) from the document when accepting revisions:

Elements to Remove

Element Name

Description

Ecma376

ISO/IEC 29500

cellIns

Table cell insertion

2.13.5.2

17.13.5.2

customXmlInsRangeStart

Content control insertion start

2.13.5.7

17.13.5.7

customXmlInsRangeEnd

Content control insertion end

2.13.5.6

17.13.5.6

del

Deleted run content

2.13.5.12

17.13.5.12

delText

Deleted text

2.3.3.7

17.3.3.7

delInstrText

Deleted field code

2.16.13

17.16.13

ins

Inserted math control character

2.13.5.17

17.13.5.17

ins

Inserted numbering properties

2.13.5.19

17.13.5.19

ins

Inserted paragraph

2.13.5.18

17.13.5.18

ins

Inserted table row

2.13.5.16

17.13.5.16

moveTo

Move destination paragraph

2.13.5.25

17.13.5.25

moveFrom

Move source run content

2.13.5.21

17.13.5.21

moveToRangeStart

Move destination location container - start

2.13.5.28

17.13.5.28

moveToRangeEnd

Move destination location container - end

2.13.5.27

17.13.5.27

numberingChange

Previous numbering field properties

2.13.5.29

17.13.5.29

numberingChange

Previous paragraph numbering properties

2.13.5.30

17.13.5.30

pPrChange

Revision information for paragraph properties

2.13.5.31

17.13.5.31

rPrChange

Revision information for run properties

2.13.5.32

17.13.5.32

rPrChange

Revision information for run properties on the paragraph mark

2.13.5.33

17.13.5.33

sectPrChange

Revision information for section properties

2.13.5.34

17.13.5.34

tblGridChange

Revision information for table grid column definitions

2.13.5.35

17.13.5.35

tblPrChange

Revision information for table properties

2.13.5.36

17.13.5.36

tblPrExChange

Revision information for table-level property exceptions

2.13.5.37

17.13.5.37

tcPrChange

Revision information for table cell properties

2.13.5.38

17.13.5.38

trPrChange

Revision information for table row properties

2.13.5.39

17.13.5.39

Collapsing Elements

You should collapse the following elements from the document when accepting revisions:

Elements to Collapse

Element Name

Description

Ecma376

ISO/IEC 29500

ins

Inserted math control character

2.13.5.17

17.13.5.17

ins

Inserted run content

2.13.5.20

17.13.5.20

ins

Inserted table row

2.13.5.16

17.13.5.16

moveTo

Move destination run content

2.13.5.26

17.13.5.26

Beyond processing elements that we can remove or collapse, there are several elements where processing involves more complex algorithms. In the following sections, I present the algorithm to process the markup. The Open XML specification does not specify these algorithms. The specification only defines the format, not any behavior associated with the format. However, you can infer some aspects of these algorithms from the specification. In the following subsections, I also present examples of the markup with the tracked revision and how the markup appears when the tracked revision is accepted.

Table Cell Deletion (cellDel Element)

This element specifies that a table cell was removed from the document.

Open XML Specification Location

Ecma-376 2.13.5.1

ISO/IEC 29500 17.13.5.1

Algorithm

To accept this revision, you remove these elements. The complication in accepting this revision is that you must group consecutive deleted cells, and increase the w:val attribute of the w:gridSpan element of the cell immediately before the group of deleted cells by the sum of the values of the w:val attributes of w:gridSpan elements of each of the deleted cells. Note that if a cell does not contain a w:gridSpan element, its grid span value is set to 1.

Example

The following example contains no w:gridSpan elements, so that the w:gridSpan values for each cell is set to 1.

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>1</w:t>
      </w:r>
    </w:p>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="3192"
             w:type="dxa"/>
      <w:cellDel w:id="3"w:author="Eric White"
                 w:date="2009-09-11T15:30:00Z"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="3192"
             w:type="dxa"/>
      <w:cellDel w:id="6"w:author="Eric White"w:date="2009-09-11T15:30:00Z"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
</w:tr>

The following example shows the resulting XML after revisions are accepted. Notice that the w:val attribute of the w:gridSpan element is set to 3, calculated as the sum of the value of the first cell (default value of 1) plus the values of the deleted cells (each with a default value of 1).

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:gridSpan w:val="3" />
      <w:tcW w:w="9576"
             w:type="dxa" />
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>1</w:t>
      </w:r>
    </w:p>
  </w:tc>
</w:tr>

Producing This Markup by Using Word 2007

Microsoft Office Word 2007 does not track revisions when merging, inserting, or deleting cells. Instead, it informs you that those revisions are not tracked. However, you can create a document that contains this markup using the following procedure:

  1. Create a document that contains a table.

  2. Copy that document to a new file, open the new document, and merge cells in the table.

  3. Save the new document.

  4. Compare the two documents by using Word 2007. Click the Review tab of the Ribbon, and then click Compare in the Compare section of the Ribbon. Click Compare two versions of a document (legal blackline). Save the resulting document without accepting changes in the document. The saved document contains the w:cellDel elements.

Note that, while Word 2007 does not produce this element without following the previous procedure, it definitely is possible in the future that an Open XML word-processing application could produce this element (and the w:cellIns element and the w:cellMerge element). It is important for this implementation to correctly process it.

Vertically Merged/Split Table Cells (cellMerge Element)

This element specifies that the vertical merge state of its parent cell was modified while revisions were tracked.

Open XML Specification Location

Ecma-376 2.13.5.3

ISO/IEC 29500 17.13.5.3

Algorithm

To accept this revision, you transform the w:cellMerge element that has an attribute of w:vMerge="rest" to the w:vMerge element that has an attribute w:val="restart". You transform the w:cellMerge element that has an attribute of w:vMerge="cont" to the w:vMerge element that has an attribute w:val="continue". To make this clear, this is what w:cellMerge with an attribute of w:vMerge="rest" looks like the following:

<w:cellMerge w:id="3"
             w:author="Eric White"
             w:date="2009-08-29T07:07:00Z"
             w:vMerge="rest" />

That element is transformed to this:

<w:vMerge w:val="restart" />

Example

The following example shows two spreadsheet rows that contain the w:cellMerge element. The example also contains w:ins elements, which are processed separately.

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>1</w:t>
      </w:r>
    </w:p>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
      <w:cellMerge w:id="3"w:author="Eric White"w:date="2009-08-29T07:07:00Z"w:vMerge="rest" />
    </w:tcPr>
    <w:p>
      <w:pPr>
        <w:rPr>
          <w:ins w:id="6"
                 w:author="Eric White"
                 w:date="2009-08-29T07:07:00Z" />
        </w:rPr>
      </w:pPr>
      <w:r>
        <w:t>2</w:t>
      </w:r>
    </w:p>
    <w:p>
      <w:ins w:id="7"
             w:author="Eric White"
             w:date="2009-08-29T07:07:00Z">
        <w:r>
          <w:t>4</w:t>
        </w:r>
      </w:ins>
    </w:p>
  </w:tc>
</w:tr>
<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>3</w:t>
      </w:r>
    </w:p>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
      <w:cellMerge w:id="9"w:author="Eric White"w:date="2009-08-29T07:07:00Z"w:vMerge="cont" />
    </w:tcPr>
    <w:p>
      <w:del w:id="12"
             w:author="Eric White"
             w:date="2009-08-29T07:07:00Z">
        <w:r>
          <w:delText>4</w:delText>
        </w:r>
      </w:del>
    </w:p>
  </w:tc>
</w:tr>

The following example shows the resulting XML that contains the w:vMerge element when this revision is accepted.

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>1</w:t>
      </w:r>
    </w:p>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
      <w:vMerge w:val="restart" />
    </w:tcPr>
    <w:p>
      <w:pPr>
        <w:rPr />
      </w:pPr>
      <w:r>
        <w:t>2</w:t>
      </w:r>
    </w:p>
    <w:p>
      <w:r>
        <w:t>4</w:t>
      </w:r>
    </w:p>
  </w:tc>
</w:tr>
<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
    </w:tcPr>
    <w:p>
      <w:r>
        <w:t>3</w:t>
      </w:r>
    </w:p>
  </w:tc>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="4788"
             w:type="dxa" />
      <w:vMerge w:val="continue" />
    </w:tcPr>
    <w:p />
  </w:tc>
</w:tr>

Producing This Markup by Using Word 2007

You can create a document that contains this markup using the following procedure:

  1. Create a document that contains a table.

  2. Copy that document to a new file, open the new document, and vertically merge cells in the table. Save the new document.

  3. Compare the two documents by using Word 2007 using the procedure that is described in the Table Cell Deletion (cellDel Element) section.

Content Control Deletion Start and End (customXmlDelRangeStart Element and customXmlDelRangeEnd Element)

These elements specify a region in the document where a content control was deleted from the document.

Open XML Specification Location

Ecma-376 2.13.5.4, 2.13.5.5

ISO/IEC 29500 17.13.5.4, 17.13.5.5

Algorithm

To accept this revision, you must find all content control elements where both the start and end tag of the content control fall inside a matched pair of the w:customXmlDelRangeStart element and the w:customXmlDelRangeEnd element. A matched pair of elements requires that both the w:customXmlDelRangeStart element and the w:customXmlDelRangeEnd element have matching w:id attributes. After a w:customXml element is identified as deleted, you must collapse the w:sdt element, promoting its content to the level of the content control element. The w:customXmlDelRangeStart element and the w:customXmlDelRangeEnd element are removed also.

One of the interesting things about this transform is that you must verify that the end tag of a content control element falls inside a range. When using an XML DOM tree, such as LINQ to XML or the classes in the System.Xml.XmlDocument namespace, you must implement a somewhat complex algorithm that would not have a direct correlation to the text of the Open XML specification. Instead, in the code to accept tracked revisions, I implemented a method that returns a collection of descendant start and end tags for a LINQ to XML element. The code that looks for the pattern where the end tag of a custom XML element is then implemented so that the logic of the method has a direct parallel to the text of the specification.

Example

The following example shows revision tracking markup for a deleted content control and its contents. As I mentioned previously, it is important that the w:id attributes match also.

<w:customXmlDelRangeStart w:id="0"
                          w:author="Eric White (OFFICE)"
                          w:date="2010-01-20T11:01:00Z"/>
<w:sdt>
  <w:sdtPr>
    <w:id w:val="63554597"/>
    <w:placeholder>
      <w:docPart w:val="DefaultPlaceholder_22675703"/>
    </w:placeholder>
  </w:sdtPr>
  <w:sdtContent>
    <w:customXmlDelRangeEnd w:id="0"/>
    <w:p>
      <w:r>
        <w:t>This is a test.</w:t>
      </w:r>
    </w:p>
  </w:sdtContent>
  <w:customXmlDelRangeStart w:id="1"
                            w:author="Eric White (OFFICE)"
                            w:date="2010-01-20T11:01:00Z"/>
</w:sdt>
<w:customXmlDelRangeEnd w:id="1"/>

The following example shows the resulting XML when this revision is accepted.

<w:p>
  <w:r>
    <w:t>This is a test.</w:t>
  </w:r>
</w:p>

Deleted Math Control Character (del Element)

This element specifies that a math control character was deleted.

Open XML Specification Location

Ecma-376 2.13.5.15

ISO/IEC 29500 17.13.5.15

Algorithm

To accept this revision, you match the pattern m:f/m:fPr/m:ctrlPr/w:del, and remove the m:f element.

Example

The following example shows a deleted math control character.

<w:p>
  <m:oMathPara>
    <m:oMath>
      <m:r>
        <w:rPr>
          <w:rFonts w:ascii="Cambria Math"
                    w:hAnsi="Cambria Math" />
        </w:rPr>
        <m:t>1+</m:t>
      </m:r>
      <m:f><m:fPr><m:ctrlPr><w:del w:id="0"w:author="Eric White"w:date="2009-09-09T15:45:00Z">
              <w:rPr>
                <w:rFonts w:ascii="Cambria Math"
                          w:hAnsi="Cambria Math" />
                <w:i />
              </w:rPr>
            </w:del>
          </m:ctrlPr>
        </m:fPr>
        <m:num>
          <w:del w:id="1"
                 w:author="Eric White"
                 w:date="2009-09-09T15:45:00Z">
            <m:r>
              <w:rPr>
                <w:rFonts w:ascii="Cambria Math"
                          w:hAnsi="Cambria Math" />
              </w:rPr>
              <m:t>2</m:t>
            </m:r>
          </w:del>
        </m:num>
        <m:den>
          <w:del w:id="2"
                 w:author="Eric White"
                 w:date="2009-09-09T15:45:00Z">
            <m:r>
              <w:rPr>
                <w:rFonts w:ascii="Cambria Math"
                          w:hAnsi="Cambria Math" />
              </w:rPr>
              <m:t>3</m:t>
            </m:r>
          </w:del>
        </m:den>
      </m:f>
    </m:oMath>
  </m:oMathPara>
</w:p>

The following example shows the resulting XML when this revision is accepted.

<w:p>
  <m:oMathPara>
    <m:oMath>
      <m:r>
        <w:rPr>
          <w:rFonts w:ascii="Cambria Math"
                    w:hAnsi="Cambria Math" />
        </w:rPr>
        <m:t>1+</m:t>
      </m:r>
    </m:oMath>
  </m:oMathPara>
</w:p>

Producing This Markup by Using Word 2007

To create a document by using this markup, insert a math formula, such as a fraction, turn on revision tracking, and delete the fraction.

Deleted Paragraph (del Element)

This element specifies that the paragraph mark for the paragraph that contains this element is deleted. In practical terms, it means that the contents of the paragraph that contains this element, and the contents of the following paragraph are combined to form a new paragraph.

Open XML Specification Location

Ecma376 2.13.5.13

ISO/IEC 29500 17.13.5.13

Algorithm

The algorithm for this is somewhat complex. More than one consecutive paragraph may contain this element. Therefore, you must group paragraphs that contain this, combine the contents of the grouped paragraphs with the paragraph following the last in the group, and form a new paragraph. The paragraph properties for the new paragraph come from the paragraph following the last in the group.

The algorithm is more complex in that any of the paragraphs with a deleted paragraph mark, or the paragraph following the last in the series may be contained in custom XML elements or in content controls. When combining the set of paragraphs, we must manipulate the custom XML elements and the content controls that are contained within the series. The rule when manipulating a content control while accepting deleted paragraph marks is that the content control should always enclose the same (non-deleted) runs as before accepting revisions. One additional addendum to this rule: if the content control was at the block level before accepting revisions, and if the content control surrounds runs that exactly match the contents of paragraphs, the content control should stay at the block level. In other words, it should not be demoted to the run level unnecessarily. The rule when manipulating custom XML elements when accepting deleted paragraph marks is that if a custom XML element was at the block level before accepting revisions, it must stay at block level after accepting revisions, even if it means moving text that was outside the custom XML element into a paragraph within the custom XML element. And of course, custom XML elements at the run level remain at the run level. The example code that is part of the PowerTools for Open XML project exhibits this behavior.

Example

The following example shows a deleted paragraph mark.

<w:p>
  <w:r>
    <w:t>On the Insert tab.</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:rPr>
      <w:del w:id="0"w:author="Eric White"w:date="2009-08-21T15:38:00Z" />
    </w:rPr>
  </w:pPr>
  <w:r>
    <w:t>You can use these.</w:t>
  </w:r>
</w:p>
<w:sdt>
  <w:sdtPr>
    <w:id w:val="283218227" />
    <w:placeholder>
      <w:docPart w:val="DefaultPlaceholder_22675703" />
    </w:placeholder>
  </w:sdtPr>
  <w:sdtContent>
    <w:p>
      <w:pPr>
        <w:rPr>
          <w:del w:id="1"w:author="Eric White"w:date="2009-08-21T15:38:00Z" />
        </w:rPr>
      </w:pPr>
      <w:r>
        <w:t>Create pictures, charts, or diagrams.</w:t>
      </w:r>
    </w:p>
  </w:sdtContent>
</w:sdt>
<w:p>
  <w:r>
    <w:t>You can easily change the formatting.</w:t>
  </w:r>
</w:p>

The following example shows the resulting XML when this revision is accepted. Because one of the paragraphs that contains the deleted paragraph mark was in a content control, the content control was demoted to enclose a run.

<w:p>
  <w:r>
    <w:t>On the Insert tab.</w:t>
  </w:r>
</w:p>
<w:p>
  <w:r>
    <w:t>You can use these.</w:t>
  </w:r>
  <w:sdt>
    <w:sdtPr>
      <w:id w:val="283218227" />
      <w:placeholder>
        <w:docPart w:val="DefaultPlaceholder_22675703" />
      </w:placeholder>
    </w:sdtPr>
    <w:sdtContent>
      <w:r>
        <w:t>Create pictures, charts, or diagrams.</w:t>
      </w:r>
    </w:sdtContent>
  </w:sdt>
  <w:r>
    <w:t>You can easily change the formatting.</w:t>
  </w:r>
</w:p>

Producing This Markup by Using Word 2007

Place the cursor at the end of a paragraph, and press Delete.

Deleted Table Row (del Element)

This element specifies that a row in a table was deleted.

Open XML Specification Location

Ecma-376 2.13.5.14

ISO/IEC 29500 17.13.5.14

Algorithm

To accept this revision, you match the pattern w:tr/w:trPr/w:del, and remove the w:tr element.

Example

The following example shows a deleted table row.

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
</w:tr>
<w:tr><w:trPr><w:del w:id="0"w:author="Eric White"w:date="2009-09-29T22:10:00Z"/>
  </w:trPr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p>
      <w:pPr>
        <w:rPr>
          <w:del w:id="1"
                 w:author="Eric White"
                 w:date="2009-09-29T22:10:00Z"/>
        </w:rPr>
      </w:pPr>
      <w:del w:id="2"
             w:author="Eric White"
             w:date="2009-09-29T22:10:00Z">
        <w:r>
          <w:delText>123</w:delText>
        </w:r>
      </w:del>
    </w:p>
  </w:tc>
</w:tr>
<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
</w:tr>

The following example shows the resulting XML when this revision is accepted. The second of the three rows is no longer present.

<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
</w:tr>
<w:tr>
  <w:tc>
    <w:tcPr>
      <w:tcW w:w="9576"
             w:type="dxa"/>
    </w:tcPr>
    <w:p/>
  </w:tc>
</w:tr>

Move Source Paragraph (moveFrom Element)

This element specifies that the paragraph mark for the paragraph that contains this element is moved. In practical terms, it means that the contents of the paragraph that contains this element, and the contents of the following paragraph are combined to form a new paragraph. If more than one consecutive paragraph contains this element, then the paragraphs are grouped together, and the code produces a new paragraph that contains the content of all grouped paragraphs, plus the content of the paragraph following the last in the group. The paragraph properties come from the paragraph following the group.

Open XML Specification Location

Ecma-376 2.13.5.22

ISO/IEC 29500 17.13.5.22

Algorithm

The algorithm for this is identical to the processing of a paragraph that has a deleted paragraph mark.

Move Source Location Container—Start and End (moveFromRangeStart Element and moveFromRangeEnd Element)

These elements specify a region in the document where content was moved from this location to another.

Open XML Specification Location

Ecma-376 2.13.5.23, 2.13.5.24

ISO/IEC 29500 17.13.5.23, 17.13.5.24

Algorithm

Processing of this revision is somewhat similar to the w:customXmlDelRangeStart and w:customXmlDelRangeEnd elements. You must find all elements where both the start and end tag of the elements fall inside a matched pair of w:moveFromRangeStart and w:moveFromRangeEnd elements. A matched pair of elements requires that both the w:moveFromRangeStart and w:moveFromRangeEnd elements have matching w:id attributes. However, different from the w:customXmlDelRangeStart and w:customXmlDelRangeEnd elements, these ranges apply to all contained content, and instead of collapsing, as the w:customXmlDelRangeStart and w:customXmlDelRangeEnd elements require, contained content is removed.

There is one more complication when you process these elements. If the end tag of a paragraph (w:p) is inside a range, but the start tag of the paragraph is not, the paragraph mark is considered deleted. This aspect of processing these elements is handled in the same manner to processing of the w:del (Deleted Paragraph Mark) element.

Example

The following example shows revision tracking markup for content that was moved away from a specific location.

<w:p>
  <w:r>
    <w:t>Hello.</w:t>
  </w:r>
</w:p>
<w:p>
  <w:moveFromRangeStart w:id="2"
                        w:author="Eric White"
                        w:date="2009-09-13T16:42:00Z"
                        w:name="move240623472" />
  <w:moveFrom w:id="3"w:author="Eric White"w:date="2009-09-13T16:42:00Z">
    <w:r>
      <w:t>Goodbye.</w:t>
    </w:r>
  </w:moveFrom>
</w:p>
<w:moveFromRangeEnd w:id="2" />
<w:p />

The following example shows the resulting XML when this revision is accepted.

<w:p>
  <w:r>
    <w:t>Hello.</w:t>
  </w:r>
</w:p>
<w:p />

Conclusion

Accepting tracked revisions is important to several Open XML scenarios. By accepting tracked revisions, we simplify the Open XML markup, and make additional processing of the markup easier. If we want to extract the content of a document for any purpose, accepting revisions first makes the job significantly easier. We may want to write server-side code to ensure that a file share or a SharePoint document library does not contain any documents that have tracked changes.

Additional Resources

For more information about how to use Open XML to work with documents, see the following resources: