Абзацы и таблица не найдены в документе Word (open XML)

#c# #ms-word #openxml

#c# #ms-word #openxml

Вопрос:

Я создал простой документ open XML (.dotx) с использованием MS Word. Файл содержит простой текст и одну таблицу. Я пытаюсь заменить несколько пользовательских заполнителей в тексте новым текстом, однако приведенный ниже фрагмент не может найти ни Paragraph в документе, ни Table в документе. Я попытался создать несколько новых файлов .dotx, а также попробовал различные варианты типа документа, т.Е. .dotx и (Strict Open XML) .docx с использованием MS Word, но проблема все еще остается.

    using (WordprocessingDocument doc =
            WordprocessingDocument.Open(templatePath, true))
        {

            var body = doc.MainDocumentPart.Document.Body;
            var paras = body.Elements<Paragraph>(); // <-- always empty
            var tables = body.Descendants<Table>(); // <-- always empty

            foreach (Table t in tables)
            {
                t.Append(new TableRow(new TableCell(new Paragraph(new Run(new Text("test"))))));
            }

            foreach (var para in paras)
            {
                foreach (var run in para.Elements<Run>())
                {
                    foreach (var text in run.Elements<Text>())
                    {
                        if (text.Text.Contains("###name###"))
                        {
                            text.Text = text.Text.Replace("###name###", "Sample");
                        }
                    }
                }
            }
            doc.SaveAs(resultPath);
        }
 

Забавно, что если я использую приведенный ниже фрагмент из MS docs, он работает, однако неясно, как добавить дополнительные строки в таблицу. Поэтому я бы предпочел использовать первый метод istead. Есть идеи, в чем может быть проблема с файлом или приведенным выше кодом?

             using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(templatePath, true))
        {
            string docText = null;
            using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
            {
                docText = sr.ReadToEnd();
            }

            Regex regexText = new Regex("###name###");
            docText = regexText.Replace(docText, "My Text!");

            using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
            {
                sw.Write(docText);
            }
        }
 

Ответ №1:

Когда вы создаете свой документ с помощью редактора, такого как MS Word, он может добавить несколько контейнеров, которые переносят ваш абзац, я бы посоветовал вам проверить сгенерированный xml. Для этого вы можете просто переименовать .docx .zip и открыть этот архив.

Внутри вы найдете такие файлы введите описание изображения здесь

Вам нужно будет открыть word/document.xml в любом текстовом редакторе и посмотреть, <w:p> есть ли и является ли он прямым дочерним элементом <w:body> . Если это не прямое, используйте descendants метод.

 var paras = body.Descendants<Paragraph>(); // <-- always empty
 

Elements находит только прямых дочерних элементов.

Descendants находит дочерние элементы на любом уровне.

Кроме того, наиболее распространенной проблемой является неправильное пространство имен, которое Paragraph существует во множестве пространств OpenXml имен, которые вы должны использовать using DocumentFormat.OpenXml.Wordprocessing;

Комментарии:

1.привет, я только что проверил это, и кажется, что -<w:body> <w:p> это прямой дочерний элемент, поскольку я в режиме тестирования могу использовать любой редактор .. можете ли вы предложить его?

2. Я имею в виду блокнот, VS Code или Atom

3. Я успешно открыл файл, и последовательность кажется правильной, как указано выше. Я также попытался воссоздать файл с помощью WordPad, и, похоже, проблема сохраняется..

4. Тогда я не вижу проблемы в вашем коде. Можете ли вы проверить свой templatePath, является ли он действительным, и ваш файл в правильном месте? И что resultPath в вашем коде?

5. да, файл действителен, поскольку я вижу, что он загружается с помощью инструкции «using»… также я использую тот же путь позже в коде .. так что никаких проблем нет.