Reputation: 420
I have an existing document. I am able to open the document in change tracking mode using TrackRevisions. Now, how can I delete a few selected paragraphs and runs as delete? I want to save document in such a state that when a user open the Word document it will display the deleted content as strikethrough and if user accepts all changes, it will remove all the deleted content.
Is it feasible to do? Any sample code would be highly appreciated. Thank you in advance!
I tried following, it generate markup with w:del element as a child of paragraph. However I am expecting all the children of paragraph under w:del element. I tried adding run elements of paragraph to deletedParagraph (commented code), but it throws error "Non-composite elements do not have child elements.".
using (var document = WordprocessingDocument.Open(@"C:\Data\Test.docx", true))
{
// Change tracking code
DocumentSettingsPart documentSettingsPart = document.MainDocumentPart.DocumentSettingsPart ?? document.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
Settings settings = documentSettingsPart.Settings ?? new Settings();
TrackRevisions trackRevisions = new TrackRevisions();
trackRevisions.Val = new DocumentFormat.OpenXml.OnOffValue(true);
settings.AppendChild(trackRevisions);
foreach(var paragraph in document.MainDocumentPart.Document.Body.Descendants<Paragraph>())
{
Deleted deletedParagraph = new Deleted();
deletedParagraph.Author = "Author Name";
deletedParagraph.Date = DateTime.Now;
paragraph.AppendChild(deletedParagraph);
foreach (var run in paragraph.Elements<Run>())
{
foreach(var text in run.Elements<Text>())
{
DeletedText deletedText = new DeletedText(text.InnerText);
run.ReplaceChild(deletedText, text);
// This throws error
//deletedParagraph.AppendChild(run.Clone() as Run);
//run.Remove();
}
}
}
document.Save();
}
The above code generates xml like this:
<w:body>
<w:p w:rsidRPr="0081286C" w:rsidR="003F5596" w:rsidP="0081286C" w:rsidRDefault="001B56FE">
<w:bookmarkStart w:name="_GoBack" w:id="0"/>
<w:bookmarkEnd w:id="0"/>
<w:r>
<w:delText>This is a sentence</w:delText>
</w:r>
<w:del w:author="Author Name" w:date="2022-07-26T07:38:26.7978264-04:00"/>
</w:p>
<w:sectPr w:rsidRPr="0081286C" w:rsidR="003F5596">
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
Upvotes: 0
Views: 520
Reputation: 420
To mark a paragraph or some text as deleted in MS Word track changes mode you need to generate the OOXml of document with following.
foreach (var text in run.Descendants<Text>().ToList())
{
DeletedText deletedText = new DeletedText(text.InnerText)
{
Space = SpaceProcessingModeValues.Preserve
};
run.ReplaceChild(deletedText, text);
}
var deleted = new Deleted
{
Author = 'RevisionAuthor',
Date = DateTime.Now
};
private static void ReplaceRunWithDelete(this Run run, Deleted deleted)
{
if(run.Descendants<FieldCode>().Any() && !run.Descendants<Deleted>().Any())
{
return;
}
var parent = run.Parent;
deleted.Id = Convert.ToString(++deletedCount);
XElement xDelete = XElement.Parse(deleted.OuterXml);
xDelete.Add(XElement.Parse(run.OuterXml));
parent.ReplaceChild(ToOpenXmlElement(xDelete), run);
}
public static OpenXmlElement ToOpenXmlElement(this XElement xElement)
{
OpenXmlElement openXmlElement = null;
using (StreamWriter sw = new StreamWriter(new MemoryStream()))
{
sw.Write(xElement.ToString());
sw.Flush();
sw.BaseStream.Seek(0, SeekOrigin.Begin);
OpenXmlReader re = OpenXmlReader.Create(sw.BaseStream);
re.Read();
openXmlElement = re.LoadCurrentElement();
re.Close();
}
return openXmlElement;
}
private static void AddDeleteToRunProps(this Paragraph paragraph, Deleted deleted)
{
// All the runs deleted so paragraph should be deleted
if (!paragraph.Descendants<Run>().Any(run => run.Descendants<Text>().Any()))
{
paragraph.ParagraphProperties ??= new ParagraphProperties();
var runProps = paragraph.ParagraphProperties.Elements<RunProperties>().Any() ? paragraph.ParagraphProperties.Elements<RunProperties>().FirstOrDefault()
: new RunProperties();
deleted.Id = Convert.ToString(++deletedCount);
runProps.AppendChild(deleted.Clone() as OpenXmlElement);
paragraph.ParagraphProperties.AppendChild(runProps);
}
}
Upvotes: 0