Вопрос по openxml, ms-word, .net, automation, c# – Вставьте OpenXmlElement после закладки слова в Open XML SDK

4

Я смог получить доступ к закладке в моем текстовом документе, используя этот код:

var res = from bm in mainPart.Document.Body.Descendants()
                              where bm.Name == "BookmarkName"
                              select bm;

Теперь я хочу вставить абзац и таблицу после этой закладки. Как я могу это сделать? (пример кода будет оценен)

Ваш Ответ

1   ответ
26

Код

Когда у вас есть закладка, вы можете получить доступ к ее родительскому элементу и добавить другие элементы после нее.

using (WordprocessingDocument document = WordprocessingDocument.Open(@"C:\Path\filename.docx", true))
{
    var mainPart = document.MainDocumentPart;
    var res = from bm in mainPart.Document.Body.Descendants()
              where bm.Name == "BookmarkName"
              select bm;
    var bookmark = res.SingleOrDefault();
    if (bookmark != null)
    {
        var parent = bookmark.Parent;   // bookmark's parent element

        // simple paragraph in one declaration
        //Paragraph newParagraph = new Paragraph(new Run(new Text("Hello, World!")));

        // build paragraph piece by piece
        Text text = new Text("Hello, World!");
        Run run = new Run(new RunProperties(new Bold()));
        run.Append(text);
        Paragraph newParagraph = new Paragraph(run);

        // insert after bookmark parent
        parent.InsertAfterSelf(newParagraph);

        var table = new Table(
        new TableProperties(
            new TableStyle() { Val = "TableGrid" },
            new TableWidth() { Width = 0, Type = TableWidthUnitValues.Auto }
            ),
            new TableGrid(
                new GridColumn() { Width = (UInt32Value)1018U },
                new GridColumn() { Width = (UInt32Value)3544U }),
        new TableRow(
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("Category Name"))
                )),
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 4788, Type = TableWidthUnitValues.Dxa }),
                new Paragraph(
                    new Run(
                        new Text("Value"))
                ))
        ),
        new TableRow(
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("C1"))
                )),
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("V1"))
                ))
        ));

        // insert after new paragraph
        newParagraph.InsertAfterSelf(table);
    }

    // close saves all parts and closes the document
    document.Close();
}

Код выше должен это сделать. Однако я'объясню некоторые особые обстоятельства.

Имейте в виду, что он попытается вставки после родительского элемента закладки. Какое поведение вы ожидаете, если ваша закладка окажется частью абзаца внутри таблицы? Должен ли он добавить новый параграф и таблицу сразу после него, внутри этой таблицы? Или он должен сделать это после этой таблицы?

Вам может быть интересно, почему вышеупомянутые вопросы имеют значение. Все зависит от того, где будет происходить вставка. Если закладкаs родитель находится в таблице, в настоящее время приведенный выше код будет пытаться поместить таблицу в таблицу. Тот'Это нормально, однако может произойти ошибка из-за неверной структуры OpenXml. Причина в том, что если вставленная таблица была последним элементом в исходной таблице 's TableCell, необходимо добавить элемент Paragraph после закрывающего тега TableCell. Вы быстро обнаружите эту проблему, если она возникла после попытки открыть документ в MS Word.

Решение состоит в том, чтобы определить, действительно ли вы выполняете вставку в таблицу.

Для этого мы можем добавить к приведенному выше коду (после родительского var):

    var parent = bookmark.Parent;   // bookmark's parent element

    // loop till we get the containing element in case bookmark is inside a table etc.
    // keep checking the element's parent and update it till we reach the Body
    var tempParent = bookmark.Parent;
    bool isInTable = false;
    while (tempParent.Parent != mainPart.Document.Body)
    {
        tempParent = tempParent.Parent;
        if (tempParent is Table && !isInTable)
            isInTable = true;
    }

    // ... 

    newParagraph.InsertAfterSelf(table);  // from above sample
    // if bookmark is in a table, add a paragraph after table
    if (isInTable)
        table.InsertAfterSelf(new Paragraph());

Это должно предотвратить возникновение ошибки и предоставить вам действительный OpenXml. Идея цикла while может быть использована, если вы ответили "да" на мой предыдущий вопрос, и хотел выполнить вставку после родительской таблицы, а не внутри таблицы, как и в приведенном выше коде. Если это'В этом случае вышеуказанная проблема больше не будет проблемой, и вы можете заменить этот цикл и логическое значение следующим:

    var parent = bookmark.Parent;   // bookmark's parent element
    while (parent.Parent != mainPart.Document.Body)
    {
        parent = parent.Parent;
    }

Это продолжает переназначать родителя доs основной содержащий элемент на уровне тела. Таким образом, если бы закладка была в абзаце, который был в таблице, она перешла бы из Paragraph в TableCell в TableRow в Table и остановилась на этом, поскольку таблицаРодитель - это Тело. В этот момент родитель = элемент таблицы, и мы можем вставить после него.

Это должно охватывать несколько разных подходов, в зависимости от вашего первоначального намерения. Дайте мне знать, если вам понадобятся какие-либо разъяснения после того, как вы попробуете.

Отражатель документа

Вам может быть интересно, как я определилGridColumn.Width ценности. Я сделал таблицу и использовал инструмент Document Reflector, чтобы получить ее. Когда вы установили Open Xml SDK, инструменты повышения производительности (если вы их установили) находились вC:\Program Files\Open XML Format SDK\V2.0\tools (или похожие).

Лучший способ узнать, как работает формат * .docx (или любой документ, отформатированный в Open Xml), - это открыть существующий файл с помощью инструмента «Отражатель документов». Перейдите к части документа и найдите элементы, которые вы хотите скопировать. Инструмент показывает вам фактический код, использованный для генерации всего документа. Это код, который вы можете скопировать / вставить в свое приложение для получения похожих результатов. Вы можете игнорировать все ссылочные идентификаторы обычно; вы'Придется взглянуть и попробовать, чтобы почувствовать это.

Как я уже упоминал, приведенный выше код таблицы был адаптирован из образца документа. Я добавил простую таблицу в docx, затем открыл ее в инструменте и скопировал код, сгенерированный инструментом (я удалил некоторые дополнительные функции, чтобы очистить его). Это дало мне рабочий образец для добавления таблицы.

Это особенно полезно, когда вы хотите знать, как писать код, который генерирует что-то, например, отформатированные таблицы и абзацы со стилями и т. Д.

Посмотрите по этой ссылке скриншоты и информацию о других инструментах, включенных в SDK:Введение в Open XML SDK 2.0.

Фрагменты кода

Вас также могут заинтересовать фрагменты кода для Open Xml. Для проверки списка фрагментовэтот блог, Вы можете скачать их здесь:Пример системы Office 2007: фрагменты кода в формате Open XML в формате SDK 2.0 для Visual Studio 2008.

После установки вы добавите их из Tools | Меню Диспетчера фрагментов кода. Выберите C # для языка, нажмите кнопку Добавить и перейдите кPersonalFolder \ Visual Studio 2008 \ Фрагменты кода \ Visual C # \ Open XML SDK 2.0 для Microsoft Office добавить их. Из вашего кода вы бы щелкните правой кнопкой мыши и выберите "Вставить фрагмент " и выберите тот, который вы хотите.

По замыслу (или определению) абзац всегда начинается с новой строки. Похоже, вы хотите добавить новый текст в закладки "родительский абзац, поэтому текст продолжается в той же строке, верно? Абзац может содержать несколькоБежит,» который в свою очередь содержит "Текст" вещь. Чтобы добавить абзац, вам нужно добавить новый прогон к нему. Если это'Что вы хотите, после создания Run var и добавления его текста, не добавляйте его вnewParagraph, Вместо этого добавьте это к родителю:parent.Append (ход); Затем добавьте таблицу после нее:parent.InsertAfterSelf (таблица); - посмотри, если этосидеть :) Ahmad Mageed

Похожие вопросы