如何根据openxmlelement获取页码

问题描述 投票:0回答:3

对于 Paragraph 对象,如何使用 Open XML SDK 2.5 确定该对象位于哪个页面?

我已经获得了文档中的所有子元素,并使用它获取了内部文本。

   foreach (var i in mainPart.Document.ChildElements.FirstOrDefault().ChildElements)
        {
            ParagraphElements.Add(i); //openxmlelement list
        }

我想获取相应段落的页码。例如,我将“这是标题 1”标记为样式标题 1,这将在目录中更新。所以我需要传递页码

提前致谢

openxml openxml-sdk tableofcontents page-numbering
3个回答
7
投票

页面在由文字处理器呈现之前并不以 OpenXML 格式存在。

计算给定段落应该出现在哪个页面上所需的元数据是可用的,但这远不是一个简单的操作。

验证原始 OpenXML 标记中不存在页码:

  1. 将以“.docx”结尾的 Word 文档副本重命名为以“.zip”结尾。
  2. 在此 zip 存档中,打开名为“word”的子目录。
  3. 在“word”中打开“document.xml”。

此文件包含您的

mainPart.Document
调用的 XML 内容。 “document.xml”文件有一个节点
<document>...</document>
,该节点又具有一个子节点
<body>...</body>
,该子节点又包含您感兴趣的内容。

在处理 OpenXML 文档时,我发现 OpenXML SDK 中的抽象有时会让人分心。值得庆幸的是,使用 LINQ-to-XML 探索原始标记很简单。例如,您致电:

var childrenFromOpenXmlSdk = mainPart.Document.ChildElements.Single().ChildElements;

相当于 LINQ-to-XML 中的以下内容:

IEnumerable<XElement> childrenFromLinqToXml = 
    XElement.Load("[path]/[file]/word/document.xml")
            .Elements()
            .Single()
            .Elements();`

检查

childrenFromLinqToXml
中的元素,你会发现没有页码信息。

您可能会在目录本身的原始标记中看到缓存页码,但这些将是先前呈现的工件,由内容标签或表单字段定义。

如果您需要以编程方式构建目录,请查看以下站点:

  1. OfficeOpenXML.com 的 TOC 参考文章

    • 这是 OpenXML ECMA-376 规范的有用参考。
  2. Eric White 的截屏视频“探索 Open XML WordprocessingML 文档中的目录”

    • Eric White 是 OpenXML 领域的权威。当您发现自己处于 XML 标记和屏幕渲染的交叉点时,他的
      ericwhite.com/blog
      非常值得一看。

--- 跟进 Sai 的评论 ---

您好 Austin Drenski,我已经创建了目录并以编程方式添加了所有标题。我所需要的只是页码。有没有其他方法可以获取特定段落的页码?我已经看完了所有的屏幕截图。但我只是在寻找页码。

<w:r> <w:fldChar w:fldCharType="begin" /> </w:r> <w:r> <w:instrText xml:space="preserve"> PAGEREF _Toc481680509 \h </w:instrText> </w:r> <w:r> <w:fldChar w:fldCharType="separate" /> </w:r> <w:r> <w:t>2</w:t> </w:r> <w:r> <w:fldChar w:fldCharType="end" /> </w:r>

在该示例 XML 2 中,“2”充当页码。这是硬编码的

现在我的目录在没有页码的情况下可以完美工作。我还分析了默认的 MS Word 功能。第一次,页码按照上面的字面意思给出。

您可以通过编程方式将内容控件

<w:sdt>
放置在文档中,作为
<w:body>
元素的子元素。

对于包含两个条目的简单目录:

<w:sdt>
    <w:sdtPr>
        <w:id w:val="429708664"/>
        <w:docPartObj>
            <w:docPartGallery w:val="Table of Contents"/>
            <w:docPartUnique/>
        </w:docPartObj>
    </w:sdtPr>
    <w:sdtContent>
        <w:p>
            <w:pPr>
                <w:pStyle w:val="TOCHeading"/>
            </w:pPr>
            <w:r>
                <w:t>Contents</w:t>
            </w:r>
        </w:p>
        <w:p>
            <w:pPr>
                <w:pStyle w:val="TOC1"/>
                <w:tabs>
                    <w:tab w:val="right" w:leader="dot" w:pos="9350"/>
                </w:tabs>
            </w:pPr>
            <w:r>
                <w:fldChar w:fldCharType="begin"/>
            </w:r>
            <w:r>
                <w:instrText xml:space="preserve"> TOC \o "1-3" \h \z \u </w:instrText>
            </w:r>
            <w:r>
                <w:fldChar w:fldCharType="separate"/>
            </w:r>
            <w:hyperlink w:anchor="_Toc481654079" w:history="1">
                <w:r>
                    <w:rPr>
                        <w:rStyle w:val="Hyperlink"/>
                    </w:rPr>
                    <w:t>Testing 1</w:t>
                </w:r>
                <w:r>
                    <w:tab/>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="begin"/>
                </w:r>
                <w:r>
                    <w:instrText xml:space="preserve"> PAGEREF _Toc481654079 \h </w:instrText>
                </w:r>
                <w:r>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="separate"/>
                </w:r>
                <w:r>
                    <w:t>0</w:t>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="end"/>
                </w:r>
            </w:hyperlink>
        </w:p>
        <w:p>
            <w:pPr>
                <w:pStyle w:val="TOC1"/>
                <w:tabs>
                    <w:tab w:val="right" w:leader="dot" w:pos="9350"/>
                </w:tabs>
            </w:pPr>
            <w:hyperlink w:anchor="_Toc481654080" w:history="1">
                <w:r>
                    <w:rPr>
                        <w:rStyle w:val="Hyperlink"/>                                
                    </w:rPr>
                    <w:t>Testing 2</w:t>
                </w:r>
                <w:r>
                    <w:tab/>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="begin"/>
                </w:r>
                <w:r>
                    <w:instrText xml:space="preserve"> PAGEREF _Toc481654080 \h </w:instrText>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="separate"/>
                </w:r>
                <w:r>
                    <w:t>0</w:t>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="end"/>
                </w:r>
            </w:hyperlink>
        </w:p>
        <w:p>
            <w:r>
                <w:fldChar w:fldCharType="end"/>
            </w:r>
        </w:p>
    </w:sdtContent>
</w:sdt>

注意指向书签的

PAGEREF
字段代码的使用。另请注意后续标记
<w:t>0</w:t>
。当文档打开并更新字段代码时,该零将被书签当前渲染的页码替换。

每次对文档进行分页时,书签的确切位置可能会发生变化。

将零替换为实例编号后,您将在标记中观察到这些实例编号。然而,这些数字只是这些字段代码的最后渲染值。

在文档设置中,您可以提示用户在打开时更新字段代码,以便目录编号准确反映当前屏幕呈现。为此,您的设置文件应类似于:

<w:settings ...namespaces ommitted...>
    <w:updateFields w:val="true"/>
    ...other settings ommitted...
</w:settings>

最终,您仍然需要使用文字处理器渲染 OpenXML 文档,但避免了计算页面位置的复杂性。


0
投票

获取当前页码

            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Begin,
            });
            runs.Append(new FieldCode(@" PAGE \* MERGEFORMAT ")
            {
                Space = SpaceProcessingModeValues.Preserve
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Separate
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.End
            });

获取总页数

            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Begin,
            });
            runs.Append(new FieldCode(@" NUMPAGES \* MERGEFORMAT ")
            {
                Space = SpaceProcessingModeValues.Preserve
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Separate
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.End
            });

完整代码

            Run runs = new Run();
            runs.Append(new Text("第"));
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Begin,
            });
            runs.Append(new FieldCode(@" PAGE \* MERGEFORMAT ")
            {
                Space = SpaceProcessingModeValues.Preserve
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Separate
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.End
            });
            runs.Append(new Text("页/共"));
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Begin,
            });
            runs.Append(new FieldCode(@" NUMPAGES \* MERGEFORMAT ")
            {
                Space = SpaceProcessingModeValues.Preserve
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.Separate
            });
            runs.Append(new FieldChar
            {
                FieldCharType = FieldCharValues.End
            });
            runs.Append(new Text("页"));
            paragraph.Append(runs);

            footer1.Append(paragraph);

            part.Footer = footer1;

文字展示 enter image description here


0
投票

经过大量的基础工作,发现,无法使用openxml元素检索页码。 我们可以近似一下。但我们不能确定。因为页码是由文字处理器布局引擎呈现的。这是在所有 OpenXML 元素传递到文字处理器之后发生的。 我们可以使用 LastRenderedPageBreak 来计算它。但我们无法确定元素的位置是否正确。

因此,我建议使用 UpdateFieldsOnOpen 或 Macro 以获得更简单的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.