【问题标题】:Replace bookmark contents in Word using OpenXml使用 OpenXml 替换 Word 中的书签内容
【发布时间】:2013-09-13 09:07:13
【问题描述】:

我找不到任何用于替换书签内容的有效代码示例。代码应该能够处理替换空书签和用预先存在的内容替换书签的情况。

例如:如果我在 Word 文档中有此文本:

“在下一个周期之间是 Bookmark1.. 在下一个周期之间是 Bookmark2..”

我想在第一个句点之间插入文本“BM1”,在下一个句点之间插入“BM2”。

第一次替换运行后,替换已正确插入。

但在下一次替换运行后,Bookmark1 之后的行上的所有文本都被删除,然后插入 Bookmark2 的替换。

这是我的 C# 代码:

    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();
        }
    }

我已经寻找了很长时间的通用解决方案。 任何帮助表示赞赏! -维克多

【问题讨论】:

    标签: ms-word openxml bookmarks


    【解决方案1】:

    也许这可以帮助你 第一:删除书签内容 第二:查找书签 => 插入值

            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;
            }
    

    【讨论】:

    • 请用英文发帖。
    【解决方案2】:

    此代码有效,但当书签放置在字段/表单文本(灰色框)内时无效。

        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);
        }
    

    【讨论】:

    • 该替换代码也适用于字段周围的书签,但如果字段太复杂则不行。这仅在这种情况下有效:当您单击灰色区域时,仅应在文字编辑器中选择灰色区域,而不是任何周围的“事物”。 -维克多
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多