Created
February 26, 2013 00:42
-
-
Save pgrm/5034752 to your computer and use it in GitHub Desktop.
How to work with bookmarks in Word OpenXML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*** EXTENSTION METHODS START ***/ | |
public static T GetFirstDescendant<T>(this OpenXmlElement parent) where T : OpenXmlElement | |
{ | |
var descendants = parent.Descendants<T>(); | |
if (descendants != null) | |
return descendants.FirstOrDefault(); | |
else | |
return null; | |
} | |
public static T GetParent<T>(this OpenXmlElement child) where T : OpenXmlElement | |
{ | |
while (child != null) | |
{ | |
child = child.Parent; | |
if (child is T) | |
return (T)child; | |
} | |
return null; | |
} | |
public static bool IsEndBookmark(this OpenXmlElement element, BookmarkStart startBookmark) | |
{ | |
return IsEndBookmark(element as BookmarkEnd, startBookmark); | |
} | |
public static bool IsEndBookmark(this BookmarkEnd endBookmark, BookmarkStart startBookmark) | |
{ | |
if (endBookmark == null) | |
return false; | |
return endBookmark.Id == startBookmark.Id; | |
} | |
/*** EXTENSTION METHODS END ***/ | |
public IDictionary<string, string> GetDocumentBookmarkValues(bool includeHiddenBookmarks = false) | |
{ | |
IDictionary<string, string> bookmarks = new Dictionary<string, string>(); | |
foreach (var bookmark in GetAllBookmarks()) | |
{ | |
if (includeHiddenBookmarks || !IsHiddenBookmark(bookmark.Name)) | |
bookmarks[bookmark.Name] = GetText(bookmark); | |
} | |
return bookmarks; | |
} | |
public void SetDocumentBookmarkValues(IDictionary<string, string> bookmarkValues) | |
{ | |
foreach (var bookmark in GetAllBookmarks()) | |
{ | |
SetBookmarkValue(bookmark, bookmarkValues); | |
} | |
} | |
private IEnumerable<BookmarkStart> GetAllBookmarks() | |
{ | |
return Document.MainDocumentPart.RootElement.Descendants<BookmarkStart>(); | |
} | |
private bool IsHiddenBookmark(string bookmarkName) | |
{ | |
return bookmarkName.StartsWith("_"); | |
} | |
public string GetText(BookmarkStart bookmark) | |
{ | |
var text = FindBookmarkText(bookmark); | |
if (text != null) | |
return text.Text; | |
else | |
return string.Empty; | |
} | |
private void SetBookmarkValue(BookmarkStart bookmark, IDictionary<string, string> bookmarkValues) | |
{ | |
string value; | |
if (bookmarkValues.TryGetValue(bookmark.Name, out value)) | |
{ | |
SetText(bookmark, value); | |
} | |
} | |
public void SetText(BookmarkStart bookmark, string value) | |
{ | |
var text = FindBookmarkText(bookmark); | |
if (text != null) | |
{ | |
text.Text = value; | |
RemoveOtherTexts(bookmark, text); | |
} | |
else | |
InsertBookmarkText(bookmark, value); | |
} | |
private Text FindBookmarkText(BookmarkStart bookmark) | |
{ | |
if (bookmark.ColumnFirst != null) | |
return FindTextInColumn(bookmark); | |
else | |
{ | |
var run = bookmark.NextSibling<Run>(); | |
if (run != null) | |
return run.GetFirstChild<Text>(); | |
else | |
{ | |
Text text = null; | |
var nextSibling = bookmark.NextSibling(); | |
while (text == null && nextSibling != null) | |
{ | |
if (nextSibling.IsEndBookmark(bookmark)) | |
return null; | |
text = nextSibling.GetFirstDescendant<Text>(); | |
nextSibling = nextSibling.NextSibling(); | |
} | |
return text; | |
} | |
} | |
} | |
private Text FindTextInColumn(BookmarkStart bookmark) | |
{ | |
var cell = bookmark.GetParent<TableRow>().GetFirstChild<TableCell>(); | |
for (int i = 0; i < bookmark.ColumnFirst; i++) | |
{ | |
cell = cell.NextSibling<TableCell>(); | |
} | |
return cell.GetFirstDescendant<Text>(); | |
} | |
private void RemoveOtherTexts(BookmarkStart bookmark, Text keep) | |
{ | |
if (bookmark.ColumnFirst != null) return; | |
Text text = null; | |
var nextSibling = bookmark.NextSibling(); | |
while (text == null && nextSibling != null) | |
{ | |
if (nextSibling.IsEndBookmark(bookmark)) | |
break; | |
foreach (var item in nextSibling.Descendants<Text>()) | |
{ | |
if (item != keep) | |
item.Remove(); | |
} | |
nextSibling = nextSibling.NextSibling(); | |
} | |
} | |
private void InsertBookmarkText(BookmarkStart bookmark, string value) | |
{ | |
bookmark.Parent.InsertAfter(new Run(new Text(value)), bookmark); | |
} |
@paulsm4 - actually the new place for that blog is http://peter.grman.at/handling-bookmarks-in-openxml-word/ - but thx for adding it here
For me the detection of IsEndBookmark
does not work (SetText
removes too much text). Changed it to this:
return endBookmark.Id.HasValue && startBookmark.Id.HasValue && (endBookmark.Id.Value == startBookmark.Id.Value);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Related links:
http://emptycode.blogspot.com/2013/02/handling-bookmarks-in-openxml-word.html
https://msdn.microsoft.com/en-us/library/bb448854.aspx