如何获取基于openxmlelement的页码

时间:2017-04-29 20:39:14

标签: openxml openxml-sdk tableofcontents page-numbering

对于Paragraph对象,如何使用Open XML SDK 2.5确定它所在的页面?

我已经获取了文档中的所有子元素,并使用此文件获取了非文本内容。

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

我想得到相应段落的页码。例如,我将“this is heading 1”标记为样式标题1,这将在TOC中更新。所以我需要传递页码

提前致谢

3 个答案:

答案 0 :(得分:3)

OpenXML格式中的页面在由字处理器呈现之前不存在。

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

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

  1. 重命名以" .docx"结尾的Word文档副本结束" .zip"。
  2. 在此zip存档中,打开名为" word"。
  3. 的子目录
  4. " word"打开" document.xml"。
  5. 此文件包含mainPart.Document来电的XML内容。 &#34; document.xml&#34;文件只有一个节点<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中的元素,您将找不到页码信息。

    您可能会在TOC本身的原始标记中看到缓存的页码,但这些是前面渲染的工件,由内容标记或表单字段定义。

    如果您需要以编程方式构建TOC,请查看以下网站:

    1. OfficeOpenXML.com's reference article for TOCs

      • 这是对OpenXML的ECMA-376规范的有用参考。
    2. Eric White's screencast "Exploring Tables-of-Contents in Open XML WordprocessingML Documents"

      • Eric White是OpenXML的主要权威。当你发现自己处于XML标记和屏幕渲染的交叉点时,他的ericwhite.com/blog非常值得一看。
    3. ---跟进赛的评论---

        

      嗨Austin Drenski,我创建了TOC并以编程方式添加了所有标题。我只需要页码。获取特定段落的页码是否有其他选择?我已经完成了所有的屏幕演员。但我一个人在寻找页码。

           

      <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&#34; 2&#34;充当页码。这是硬编码的

           

      现在我的TOC在没有Pagenumber的情况下完美运行。我还分析了默认的MS字功能。第一次,页面编号实际上是如上所述。

      您可以编辑方式将内容控件<w:sdt>放置在文档中,作为<w:body>元素的子项。

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

      <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>。打开文档并更新字段代码时,此零将替换为书签当前呈现的页码。

      每次对文档进行分页时,书签的确切位置都可以更改。

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

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

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分: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