Skip to content

Instantly share code, notes, and snippets.

@pgrm
Created February 26, 2013 00:42
Show Gist options
  • Save pgrm/5034752 to your computer and use it in GitHub Desktop.
Save pgrm/5034752 to your computer and use it in GitHub Desktop.
How to work with bookmarks in Word OpenXML
/*** 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);
}
@pgrm
Copy link
Author

pgrm commented Jan 3, 2018

@paulsm4 - actually the new place for that blog is http://peter.grman.at/handling-bookmarks-in-openxml-word/ - but thx for adding it here

@flensrocker
Copy link

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