簡體   English   中英

C#openxml刪除段落

[英]C# openxml removal of paragraph

我試圖使用OpenXML從.docx文件中刪除段落(我使用一些占位符文本從docx模板類文件生成),但每當我刪除段落時,它都會破壞我用來迭代的foreach循環。

MainDocumentPart mainpart = doc.MainDocumentPart;
IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants();

foreach(OpenXmlElement elem in elems){
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##")
    {
        Run run = (Run)elem.Parent;
        Paragraph p = (Paragraph)run.Parent;
        p.RemoveAllChildren();
        p.Remove();
    }
}

這工作,刪除我的占位符和它所在的段落, 但foreach循環停止迭代 在foreach循環中我需要做更多的事情。

這是使用的OpenXML和為什么我的foreach循環停止或如何使它不能停下來取消C#段確定方法是什么? 謝謝。

這是“萬聖節問題”,之所以這么稱呼,是因為一些開發人員在萬聖節時就注意到了這一點,看起來它們看起來很怪異。 這是使用聲明性代碼(查詢)同時使用命令式代碼(刪除節點)的問題。 如果你考慮一下,你正在迭代一個鏈表,如果你開始刪除鏈表中的節點,你就完全弄亂了迭代器。 避免此問題的一種更簡單的方法是在列表中“實現”查詢結果,然后您可以遍歷列表,並隨意刪除節點。 以下代碼的唯一區別是它在調用Descendants軸后調用ToList。

MainDocumentPart mainpart = doc.MainDocumentPart; 
IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants().ToList(); 

foreach(OpenXmlElement elem in elems){ 
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##") 
    { 
        Run run = (Run)elem.Parent; 
        Paragraph p = (Paragraph)run.Parent; 
        p.RemoveAllChildren(); 
        p.Remove(); 
    } 
} 

但是,我必須注意,我在您的代碼中看到了另一個錯誤。 沒有什么可以阻止Word將該文本節點從多個運行拆分為多個文本元素。 雖然在大多數情況下,您的代碼可以正常工作,但是您或用戶遲早會采取某些操作(例如選擇一個字符,並且不小心點擊功能區上的粗體按鈕),然后您的代碼將不再有效。

如果你真的想在文本級別工作,那么你需要使用代碼,比如我在這個屏幕上演示的代碼: http//openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/04/引入-textreplacer-A-新級換電動工具換開xml.aspx

事實上,我相信你可能會逐字地使用該代碼來處理你的用例。

另一種更靈活,更強大的方法詳述如下:

http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/06/13/open-xml-presentation-generation-using-a-template-presentation.aspx

雖然該screen-cast是關於PresentationML的,但同樣的原則適用於WordprocessingML。

但是,鑒於您使用的是WordprocessingML,更好的方法是使用內容控件。 有關文檔生成的一種方法,請參閱:

http://ericwhite.com/blog/map/generating-open-xml-wordprocessingml-documents-blog-post-series/

有關一般使用內容控件的大量信息,請參閱:

http://www.ericwhite.com/blog/content-controls-expanded

-Eric

首先必須使用兩個循環來存儲要刪除的項目,然后再刪除項目。 這樣的事情:

List<Paragraph> paragraphsToDelete = new List<Paragraph>();
foreach(OpenXmlElement elem in elems){
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##")
    {
        Run run = (Run)elem.Parent;
        Paragraph p = (Paragraph)run.Parent;
        paragraphsToDelete.Add(p);
    }
}

foreach (var p in paragraphsToDelete)
{
        p.RemoveAllChildren();
        p.Remove();
}
Dim elems As IEnumerable(Of OpenXmlElement) = MainPart.Document.Body.Descendants().ToList()
        For Each elem As OpenXmlElement In elems
            If elem.InnerText.IndexOf("fullname") > 0 Then
                elem.RemoveAllChildren()
            End If

        Next

暫無
暫無

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

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