在开放XML SDK字书签之后插入OpenXmlElement [英] Insert OpenXmlElement after word bookmark in Open XML SDK

查看:584
本文介绍了在开放XML SDK字书签之后插入OpenXmlElement的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以用这个code访问书签我的word文档中:

I was able to access a bookmark in my word document using this code:

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

现在我要插入此书签后一个段落和一张桌子。我怎么做? (例如code将AP preciated)

Now I want to insert a paragraph and a table after this bookmark. How do I do that? (example code would be appreciated)

推荐答案

code

一旦你的书签,您可以访问它的父元素和之后添加其他项目。

Once you have the bookmark you can access its parent element and add the other items after it.

using (WordprocessingDocument document = WordprocessingDocument.Open(@"C:\Path\filename.docx", true))
{
    var mainPart = document.MainDocumentPart;
    var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>()
              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();
}

以上code应该这样做。不过,我会介绍一些特殊情况。

The above code should do it. However, I'll explain some special circumstances.

请注意,它将书签的父元素之后尝试插入。你期望的行为,如果你的书签恰好是一个表内的一个段落的一部分?它应该追加新的段落和表后马上,该表内?还是应了表之后呢?

Be aware that it will attempt the insertions after the parent element of the bookmark. What behavior do you expect if your bookmark happens to be part of a paragraph inside a table? Should it append the new paragraph and table right after it, within that table? Or should it do it after that table?

您可能想知道为什么上述问题无关紧要。这一切都取决于在哪里将发生的插入。如果书签的父母是表中,目前上述code会试图将表内的表。这很好,但是一个错误,可能会出现由于无效OPENXML结构。其原因是,如果插入的表是原始表的TableCell的最后一个元素,需要有闭幕的TableCell标签之后增加了一个段落元素。你会及时发现此问题,如果它发生了,一旦你试图在MS Word中打开文档。

You might be wondering why the above questions matter. It all depends on where the insertion will occur. If the bookmark's parent is in a table, currently the above code would attempt to place a table within a table. That's fine, however an error might occur due to an invalid OpenXml structure. The reason is that if the inserted table was the last element in the original table's TableCell, there needs to be a Paragraph element added after the closing TableCell tag. You would promptly discover this issue if it occurred once you attempted to open the document in MS Word.

解决的办法是确定是否确实是一个表中进行插入。

The solution is to determine whether you are indeed performing the insertion within a table.

要做到这一点,我们可以添加上述code(父VAR后):

To do so, we can add to the above code (after the parent 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());

这应该prevent错误发生,给你有效OPENXML。如果你回答是我先前的问题,并希望父表之后,而不是在表内作为上述code会做执行插入while循环的想法都可以使用。如果是这样的情况下,上述问题将不再是一个问题,你可以替换循环与以下布尔:

That should prevent the error from occurring and give you valid OpenXml. The while loop idea can be used if you answered "yes" to my earlier question and wanted to perform the insertion after the parent table rather than inside the table as the above code would do. If that's the case, the above issue would no longer be a concern and you can replace that loop and boolean with the following:

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

这使得重新分配父,直到它在身体层面主要包含的元素。因此,如果书签是一个段落,这是在一个表中,它会从款到TableCell的去为tablerow表和停在那里,因为表的父是身体。在这一点上父表=元素,我们可以在其后插入。

This keeps re-assigning the parent till it's the main containing element at the Body level. So if the bookmark was in a paragraph that was in a table, it would go from Paragraph to TableCell to TableRow to Table and stop there since the Table's parent is the Body. At that point parent = Table element and we can insert after it.

这应该涉及到一些不同的方法,这取决于你的原意。让我知道,如果你想出来后需要的任何澄清。

That should cover some different approaches, depending on your original intent. Let me know if you need any clarification after trying it out.

文件反射

您可能想知道我是怎么确定的 GridColumn.Width 值。我做了一个表,使用的文档反射工具来得到它。当你安装了开放式XML SDK,生产力工具(如果安装了他们)将位于 C:\\ Program Files文件\\ Open XML格式SDK \\ V2.0 \\工具 (或类似)。

You might be wondering how I determined the GridColumn.Width values. I made a table and used the Document Reflector tool to get it. When you installed the Open Xml SDK, the productivity tools (if you installed them) would be located in C:\Program Files\Open XML Format SDK\V2.0\tools (or similar).

最好的方式来学习的.docx *作品格式(或任何开放XML格式DOC)如何打开与文档反射工具现有文件。浏览文档的一部分,并找到您要复制的项目。该工具向您展示了用于生成整个文档的实际code。这是code您可以复制/粘贴到您的应用程序产生类似的结果。您可以忽略所有通常参考的ID;你必须看看,并尝试一下以获取它的感觉。

The best way to learn how the *.docx format works (or any Open Xml formatted doc) is to open an existing file with the Document Reflector tool. Navigate the document part, and locate the items you want to replicate. The tool shows you the actual code used to generate the entire document. This is code you can copy/paste into your application to generate similar results. You can ignore all the reference IDs usually; you'll have to take a look and try it out to get a feel for it.

正如我所提到的,上面的表code改编自一个样本文档。我添加了一个简单的表到DOCX,然后在工具打开了它,并复制工具生成的code(我删除了一些群众演员把它清理干净)。这给了我一个工作样品添加表。

As I mentioned, the above Table code was adapted from a sample document. I added a simple table to a docx, then opened it in the tool, and copied the code generated by the tool (I removed some extras to clean it up). That gave me a working sample to add a table.

当你想知道如何写code产生的东西,如格式化表格和段落样式等,是特别有帮助。

It is especially helpful when you want to know how to write code that generates something, such as formatted tables and paragraphs with styles etc.

看看此链接的SDK中包含的其他工具的截图和信息:介绍为Open XML SDK 2.0

Take a look at this link for screenshots and info on the other tools included in the SDK: An introduction to Open XML SDK 2.0.

code片段

您可能也有兴趣在code段开放XML。对于片段列表检查<一个href=\"http://blogs.msdn.com/erikaehrli/archive/2009/08/28/open-xml-sdk-2-0-august-ctp-and-50-open-xml-$c$c-samples.aspx\">this博客文章。你可以从这里下载:<一href=\"http://www.microsoft.com/downloads/details.aspx?FamilyID=78bea298-a3f9-44cf-bde0-b4f30dc986df&displaylang=en\">2007 Office系统示例:Open XML格式SDK 2.0 code片段为Visual Studio 2008

You might also be interested in the code snippets for Open Xml. For a list of snippets check this blog post. You can download them from here: 2007 Office System Sample: Open XML Format SDK 2.0 Code Snippets for Visual Studio 2008.

一旦安装,你会从工具将它们添加| code段管理器菜单。选择C#的语言,单击添加按钮,并导航到的 PersonalFolder \\ Visual Studio 2008的\\ code片段\\的Visual C#\\的Open XML SDK 2.0的Microsoft Office 的补充它们。从code,你会用鼠标右键单击,选择插入代码段,并选择您想要的。

Once installed you would add them from Tools | Code Snippet Manager menu. Select C# for the language, click the Add button, and navigate to PersonalFolder\Visual Studio 2008\Code Snippets\Visual C#\Open XML SDK 2.0 for Microsoft Office to add them. From your code you would right-click and select "Insert Snippet" and select the one you want.

这篇关于在开放XML SDK字书签之后插入OpenXmlElement的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆