Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#openxml删除段落_C#_Openxml - Fatal编程技术网

C#openxml删除段落

C#openxml删除段落,c#,openxml,C#,Openxml,我试图使用OpenXML从.docx文件中删除段落(我使用一些占位符文本从docx模板文件生成),但每当我删除段落时,它就会中断我用来迭代的foreach循环 MainDocumentPart mainpart = doc.MainDocumentPart; IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants(); foreach(OpenXmlElement elem in elems){

我试图使用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();
    }
}
MainDocumentPart mainpart=doc.MainDocumentPart;
IEnumerable elems=mainPart.Document.Body.subjects();
foreach(元素中的OpenXmlElement元素){
if(elem为Text&&elem.InnerText==“############”)
{
Run=(Run)elem.Parent;
段落p=(段落)run.Parent;
p、 移除所有儿童();
p、 删除();
}
}
这样做可以删除我的占位符和它所在的段落,但是foreach循环停止迭代。我需要在我的foreach循环中做更多的事情


使用OpenXML和删除C#中的段落是否合适?为什么我的foreach循环停止,或者如何使它不停止?谢谢。

您必须使用两个循环,第一个循环存储要删除的项目,第二个循环删除项目。 大概是这样的:

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();
}
列表段落删除=新建列表();
foreach(元素中的OpenXmlElement元素){
if(elem为Text&&elem.InnerText==“############”)
{
Run=(Run)elem.Parent;
段落p=(段落)run.Parent;
删除.添加(p)段;
}
}
foreach(第段删除中的变量p)
{
p、 移除所有儿童();
p、 删除();
}
这就是所谓的“万圣节问题”,之所以这样称呼,是因为一些开发人员在万圣节前夜注意到了这一点,而且他们觉得这很可怕。这是同时使用声明性代码(查询)和命令性代码(删除节点)的问题。如果你仔细想想,你是在一个链表中迭代,如果你开始删除链表中的节点,你会把迭代器搞得一团糟。避免此问题的一种更简单的方法是在列表中“具体化”查询结果,然后可以在列表中迭代,并随意删除节点。以下代码中唯一的区别是,它在调用子体轴之后调用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(); 
    } 
} 
MainDocumentPart mainpart=doc.MainDocumentPart;
IEnumerable elems=mainPart.Document.Body.subjects().ToList();
foreach(元素中的OpenXmlElement元素){
if(elem为Text&&elem.InnerText==“############”)
{ 
Run=(Run)elem.Parent;
段落p=(段落)run.Parent;
p、 移除所有儿童();
p、 删除();
} 
} 
但是,我必须注意,我在代码中看到了另一个bug。没有什么可以阻止Word从多次运行中将该文本节点拆分为多个文本元素。虽然在大多数情况下,您的代码可以正常工作,但您或用户迟早会采取一些措施(例如选择角色,并意外地点击功能区上的粗体按钮),然后您的代码将不再工作

如果您真的想在文本级别工作,那么您需要使用代码,如我在本屏幕演示中介绍的代码:

事实上,我相信,您可能可以使用该代码逐字处理您的用例

另一种更灵活、更强大的方法详见:

虽然这个屏幕投射是关于PresentationML的,但同样的原则也适用于WordprocessingML

但如果您使用的是WordprocessingML,那么更好的方法是使用内容控件。有关生成文档的一种方法,请参见:

有关一般使用内容控件的详细信息,请参阅:


-埃里克

天哪,我真蠢。谢谢但为什么它会从循环中断裂呢?(如果有人知道,我会留些时间接受答案;sry不能投票,代表太低)谢谢。找到了另一个好的解决方案:实际上我已经完成了.ToList(),因为使用以前的解决方案时出现了一些其他复杂情况。另外,我知道word将其拆分为多个运行(这里的例子很糟糕),因此我的占位符没有“\ux”。我的占位符是硬编码的,所以尽管我知道内容控制的优势,但我没有使用它们,因为我对它们了解不够,并且项目进度很短(迷你)。谢谢你的回答,它很有洞察力,更完整。
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