簡體   English   中英

當書簽有很多段落(行)時,如何用openxml和c#替換書簽的文本

[英]How I can replace text of bookmark when bookmark is many paragraphs (lines) with openxml and c#

我嘗試使用openxml替換書簽的文本。 它僅適用於每個段落的第一行和單個行。

我的代碼:

foreach (BookmarkStart bookMarkStart in wordprocessingDocument.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
    if (bookMarkStart.Name == "signet")
    {
        OpenXmlElement elem = bookMarkStart.NextSibling();

        while (elem != null && !(elem is BookmarkEnd))
        {
            OpenXmlElement nextElem = elem.NextSibling();
            elem.Remove();
            elem = nextElem;
        }

        bookMarkStart.Parent.InsertAfter<Run>(new Run(new Text("teeeest")), bookMarkStart);
    }
}

以下是使用工具的xml文件。 在這里,我有兩段,但是只有第一段被替換,並且我使用id=0的書簽,第二段是自動添加的

<w:body>
    <w:p w:rsidR="0028616D" w:rsidRDefault="005537D9">
      <w:bookmarkStart w:name="signet" w:id="0" />
      <w:r>
        <w:t>Test1</w:t>
      </w:r>
    </w:p>
    <w:p w:rsidR="005537D9" w:rsidRDefault="005537D9">
      <w:r>
        <w:t>Test2</w:t>
      </w:r>
      <w:bookmarkStart w:name="_GoBack" w:id="1" />
      <w:bookmarkEnd w:id="0" />
      <w:bookmarkEnd w:id="1" />
    </w:p>
    <w:sectPr w:rsidR="005537D9">
      <w:pgSz w:w="11906" w:h="16838" />
      <w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0" />
      <w:cols w:space="708" />
      <w:docGrid w:linePitch="360" />
    </w:sectPr>
 </w:body>

這里的代碼完全適合您顯示的XML結構:書簽段落的開頭和結尾,段落的開頭和結尾處。 還有許多其他變體,每個變體都必須明確地加以滿足。

書簽由起點和終點組成。 您需要兩者才能獲取內容。

由於文檔可以具有多個書簽,並且書簽可以重疊,因此有必要獲取書簽的Id ,以標識哪個端點與起點匹配。 該名稱僅出現在BookmarkStart元素中。 在開始和結束元素中僅使用Id

有必要確定書簽的起點和終點在何處(以哪種結構),因為這提供了有關父元素,同級元素和子元素可以是什么的信息。 對於此特定用例,由於書簽的開始和結尾都在段落內,所以兩者的父級都是“ Paragraph元素。 下面的代碼通過檢查Parent.LocalName來確定這一點。

在這種情況下,將確定起點和終點的父段。 為了編輯書簽中所有段落的內容,創建了一個List 起點的父段被添加到其中。 創建一個附加的Paragraph對象,以檢查下一個同級段落,並檢查書簽的端點。 只要書簽結尾不在下一個同級段落的對象中,就執行while循環; 下一個兄弟姐妹將添加到List

一旦直到(包括)書簽末尾的所有段落都在ListList就會循環以替換每個段落中的文本。 復制第一個Run ,以保留基本的段落格式。 然后刪除所有Run和“ Text元素,復制的Run將附加新的文本。

最后,將書簽結尾設置為最后一段的結尾。

    private void btnReplaceBookmarkText_Click(object sender, EventArgs e)
    {
        string fileNameDoc = "path name";
        string bkmName = "signet";
        string bkmID = "";
        string parentTypeStart = "";
        string parentTypeEnd = "";
        using (WordprocessingDocument pkgDoc = WordprocessingDocument.Open(fileNameDoc, true))
        {
            Body body = pkgDoc.MainDocumentPart.Document.Body;
            BookmarkStart bkmStart = body.Descendants<BookmarkStart>().Where(bkm => bkm.Name == bkmName).FirstOrDefault();
            bkmID = bkmStart.Id;
            BookmarkEnd bkmEnd = body.Descendants<BookmarkEnd>().Where(bkm => bkm.Id == bkmID).FirstOrDefault();
            parentTypeStart = bkmStart.Parent.LocalName;
            parentTypeEnd = bkmEnd.Parent.LocalName;
            int counter = 0;
            if (parentTypeStart == "p" && parentTypeEnd == "p") 
            { //bookmark starts at a paragraph and ends within a paragraph
                Paragraph bkmParaStart = (Paragraph) bkmStart.Parent;
                Paragraph bkmParaEnd = (Paragraph) bkmEnd.Parent;
                Paragraph bkmParaNext = (Paragraph) bkmParaStart; 
                List<Paragraph> paras = new List<Paragraph>();
                paras.Add(bkmParaStart);

                BookmarkEnd x = bkmParaNext.Descendants<BookmarkEnd>().Where(bkm => bkm.Id == bkmID).FirstOrDefault();
                while (x==null) 
                {
                    Paragraph nextPara = (Paragraph) bkmParaNext.NextSibling();
                    if (nextPara != null)
                    {
                        paras.Add(nextPara);
                        bkmParaNext = (Paragraph)nextPara.Clone();
                        x = bkmParaNext.Descendants<BookmarkEnd>().Where(bkm => bkm.Id == bkmID).FirstOrDefault();
                    }
                }
                foreach (Paragraph para in paras)
                {
                    string t = "changed string once more " + counter;
                    Run firstRun = para.Descendants<Run>().FirstOrDefault();
                    Run newRun = (Run) firstRun.Clone();
                    newRun.RemoveAllChildren<Text>();
                    para.RemoveAllChildren<Run>();
                    para.RemoveAllChildren<Text>();
                    para.AppendChild<Run>(newRun).AppendChild<Text>(new Text(t));
                }
                //After replacing the runs and text the bookmark is at the beginning
                //of the paragraph, we want it at the end
                BookmarkEnd newBkmEnd = new BookmarkEnd() { Id = bkmID };
                Paragraph p = paras.Last<Paragraph>();
                p.Descendants<BookmarkEnd>().Where(bkm => bkm.Id==bkmID).FirstOrDefault().Remove();
                p.Append(newBkmEnd);
            }
        }  
    }

注意:由於我比Word XML更熟悉Word對象模型,因此代碼可能會更優化,但對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM