Reputation: 105
I'm looking for fast code to delete bookmarks from docx file opened in MS Word.
Now, I am using simple VBA macro with some experience-based improvement.
Public Sub RemoveBookmarks(ByRef doc As Document)
Dim b As Bookmark
Dim i As Long
For Each b In doc.Bookmarks
b.Delete
'There were documents freeze Word after delete only 4 bookmarks
i = i + 1
If i Mod 4 = 0 Then
doc.UndoClear
End If
'to handle possible Ctrl+Break
If i Mod 100 = 0 Then
DoEvents
End If
Next b
Set b = Nothing
End Sub
Very often my colleagues have large documents (over 1,2k pages) with 25k and more bookmarks. Delete this bookmarks take a lot of time.
Delete bookmarks using DocumentOpenXml and manipulate WordProcessingDocument is very fast:
public static void RemoveAllBookmarks(string fileName)
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(fileName, true))
{
var d = wordDoc.MainDocumentPart.Document;
var bstart = d.Descendants<BookmarkStart>().ToList();
foreach (var s in bstart)
s.Remove();
var bend = d.Descendants<BookmarkEnd>().ToList();
foreach (var e in bend)
e.Remove();
d.Save();
wordDoc.Save();
}
}
but I want to avoid close and open document in Word again, because adding and removing bookmarks is a part of larger proces. I don't want (I don't think I can) predict whether the document preparation process will be faster: just delete using VBA or close, remove and open huge file several times.
Maybe there is the solution to manipulate WordprocessingDocument underneath opened document and insert xml.
Upvotes: 0
Views: 419
Reputation: 2299
If you want to transform the already opened Word document, you can use the WordOpenXML
property of a Document
or Range
instance to get the document's or range's Open XML markup in the Flat OPC format. You can then work with that XML string in the following ways:
DocumentFormat.OpenXml
NuGet package (Open XML SDK), you can turn the Flat OPC string into a WordprocessingDocument
and transform it as you described.System.Xml.Linq
) and the DocumentFormat.OpenXml.Linq
NuGet package, you can turn it into an XElement
and transform it without having to turn it into a WordprocessingDocument
Once you have transformed the markup, you can turn it back into a Flat OPC string and insert it back into the Word document, using the Range.InsertXML()
method.
Transforming Open XML markup is one or two orders of magnitude faster than using the COM APIs, if you need many COM calls to create the desired result. Note, though, that retrieving the Open XML markup from an opened document and inserting it back into the document is also not free.
Upvotes: 1
Reputation: 7860
Whenever you delete items from a collection you need to start from the end and work backwards.
Public Sub RemoveBookmarks(ByRef doc As Document)
Dim b As Long
For b = doc.Bookmarks.Count To 1 Step -1
doc.Bookmarks(b).Delete
Next b
End Sub
Upvotes: 1