Replace bookmark contents in Word using OpenXml

ぐ巨炮叔叔 提交于 2019-12-12 04:35:20

问题


I can't find any working code examples for replacing bookmark contents. The code should be able to handle both the case replace empty bookmark and replace bookmark with preexisting content.

For example: If I have this text in a Word document:

"Between the following periods comes Bookmark1.. Between next periods comes Bookmark2.."

and I want to insert the text "BM1" between the first periods, and "BM2" between the next.

After the first replacement run, the replacements are inserted correctly.

But after the next replacement run, all of the text on the line after Bookmark1 gets deleted, and then the replacement for Bookmark2 gets inserted.

This is my c# code:

    var doc = WordprocessingDocument.Open(@"file.docx", true);

    public static Dictionary<string, wd.BookmarkStart> FindAllBookmarksInWordFile(WordprocessingDocument file)
    {
        var bookmarkMap = new Dictionary<String, wd.BookmarkStart>();


        foreach (var headerPart in file.MainDocumentPart.HeaderParts)
        {
            foreach (var bookmarkStart in headerPart.RootElement.Descendants<wd.BookmarkStart>())
            {
                if (!bookmarkStart.Name.ToString().StartsWith("_"))
                    bookmarkMap[bookmarkStart.Name] = bookmarkStart;
            }
        }

        foreach (var bookmarkStart in file.MainDocumentPart.RootElement.Descendants<wd.BookmarkStart>())
        {
            if (!bookmarkStart.Name.ToString().StartsWith("_"))
                bookmarkMap[bookmarkStart.Name] = bookmarkStart;
        }


        return bookmarkMap;
    }
    /*extension methods*/
    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.Value == startBookmark.Id.Value;
    }
    /* end of extension methods */

    public static void SetText(BookmarkStart bookmark, string value)
    {
        RemoveAllTexts(bookmark);

        bookmark.Parent.InsertAfter(new Run(new Text(value)), bookmark);
    }

    private static void RemoveAllTexts(BookmarkStart bookmark)
    {
        if (bookmark.ColumnFirst != null) return;

        var nextSibling = bookmark.NextSibling();

        while (nextSibling != null)
        {
            if (nextSibling.IsEndBookmark(bookmark) || nextSibling.GetType() == typeof(BookmarkStart))
                break;

            foreach (var item in nextSibling.Descendants<Text>())
            {
                item.Remove();
            }
            nextSibling = nextSibling.NextSibling();
        }
    }

I have looked around a long time for a general solution. Any help is appreciated! -Victor


回答1:


This code works but not when the bookmark is placed within a field/formtext (a gray box).

    private static void SetNewContents(wd.BookmarkStart bookmarkStart, string text)
    {
        if (bookmarkStart.ColumnFirst != null) return;

        var itemsToRemove = new List<OpenXmlElement>();

        var nextSibling = bookmarkStart.NextSibling();

        while (nextSibling != null)
        {

            if (IsEndBookmark(nextSibling, bookmarkStart))
                break;

            if (nextSibling is wd.Run)
                itemsToRemove.Add(nextSibling);

            nextSibling = nextSibling.NextSibling();
        }

        foreach (var item in itemsToRemove)
        {
            item.RemoveAllChildren();
            item.Remove();
        }

        bookmarkStart.Parent.InsertAfter(new wd.Run(new wd.Text(text)), bookmarkStart);
    }



回答2:


Maybe this can help you first:delete bookmarkContent second:find bookMark => insert value

        public static void InsertTest1(WordprocessingDocument doc, string bookMark, string txt)
            {
                try
                {
                    RemoveBookMarkContent(doc, bookMark);

                    MainDocumentPart mainPart = doc.MainDocumentPart;

                    BookmarkStart bmStart = findBookMarkStart(doc, bookMark);
                    if (bmStart == null)
                    {
                        return;
                    }
                    Run run = new Run(new Text(txt));
                    bmStart.Parent.InsertAfter<Run>(run, bmStart);
                }
                catch (Exception c)
                {
                    //not Exception
                }
            }
    public static void RemoveBookMarkContent(WordprocessingDocument doc, string bmName)
            {
                BookmarkStart bmStart = findBookMarkStart(doc, bmName);
                BookmarkEnd bmEnd = findBookMarkEnd(doc, bmStart.Id);
                while (true)
                {
                    var run = bmStart.NextSibling();
                    if (run == null)
                    {
                        break;
                    }
                    if (run is BookmarkEnd && (BookmarkEnd)run == bmEnd)
                    {
                        break;
                    }

                    run.Remove();
                }
            }
private static BookmarkStart findBookMarkStart(WordprocessingDocument doc, string bmName)
        {
            foreach (var footer in doc.MainDocumentPart.FooterParts)
            {
                foreach (var inst in footer.Footer.Descendants<BookmarkStart>())
                {
                    if (inst.Name == bmName)
                    {
                        return inst;
                    }
                }
            }

            foreach (var header in doc.MainDocumentPart.HeaderParts)
            {
                foreach (var inst in header.Header.Descendants<BookmarkStart>())
                {
                    if (inst.Name == bmName)
                    {
                        return inst;
                    }
                }
            }
            foreach (var inst in doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
            {
                if (inst is BookmarkStart)
                {
                    if (inst.Name == bmName)
                    {
                        return inst;
                    }
                }
            }

            return null;
        }


来源:https://stackoverflow.com/questions/18782436/replace-bookmark-contents-in-word-using-openxml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!