2009-12-21 289 views

回答

24

OpenXML中的列表有点混淆。

有一个NumberingDefinitions部分描述文档中的所有列表。它包含有关列表应该如何显示(项目符号,编号等)以及每个项目分配和ID的信息。

然后在MainDocumentPart中,对于要创建的列表中的每个项目,都需要添加一个新段落并将该列表的ID分配给该段落。

所以要建立一个符号列表,例如:

  • 你好,
  • 世界!

您必须首先创建一个NumberingDefinitionsPart:

NumberingDefinitionsPart numberingPart = 
    mainDocumentPart.AddNewPart<NumberingDefinitionsPart>("someUniqueIdHere"); 

Numbering element = 
    new Numbering(
    new AbstractNum(
     new Level(
     new NumberingFormat() {Val = NumberFormatValues.Bullet}, 
     new LevelText() {Val = "·"} 
    ) {LevelIndex = 0} 
    ){AbstractNumberId = 1}, 
    new NumberingInstance(
     new AbstractNumId(){Val = 1} 
    ){NumberID = 1}); 

element.Save(numberingPart); 

然后创建MainDocumentPart像往常一样,除了在段落属性,分配的编号ID:

MainDocumentPart mainDocumentPart = 
    package.AddMainDocumentPart(); 

Document element = 
    new Document(
    new Body(
     new Paragraph(
     new ParagraphProperties(
      new NumberingProperties(
      new NumberingLevelReference(){ Val = 0 }, 
      new NumberingId(){ Val = 1 })), 
     new Run(
      new RunProperties(), 
      new Text("Hello, "){ Space = "preserve" })), 
     new Paragraph(
     new ParagraphProperties(
      new NumberingProperties(
      new NumberingLevelReference(){ Val = 0 }, 
      new NumberingId(){ Val = 1 })), 
     new Run(
      new RunProperties(), 
      new Text("world!"){ Space = "preserve" })))); 

element.Save(mainDocumentPart); 

第2.9节中对OpenXML reference guide中提供的选项有更好的解释。

3

以上亚当的回答是,除了它正确的是新NumberingInstance(而不是新的NUM(如在注释中提到。

此外,如果您有多个列表,你应该有多个编号的元素(每个都有它自己的ID例如1,2,3等 - 对于文档中的每个列表,这似乎没有问题,但编号列表将继续使用相同的编号顺序(而不是从1重新开始)因为它会认为它是相同的列表。NumberingId必须在您的段落中引用,如下所示:

ParagraphProperties paragraphProperties1 = new ParagraphProperties(); 
ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "ListParagraph" }; 
NumberingProperties numberingProperties1 = new NumberingProperties(); 
NumberingLevelReference numberingLevelReference1 = new NumberingLevelReference() { Val = 0 }; 

NumberingId numberingId1 = new NumberingId(){ Val = 1 }; //Val is 1, 2, 3 etc based on your numberingid in your numbering element 
numberingProperties1.Append(numberingLevelReference1); 
numberingProperties1.Append(numberingId1); 
paragraphProperties1.Append(paragraphStyleId1); 
paragraphProperties1.Append(numberingProperties1); 

Level元素的子元素将对子弹类型和缩进产生影响。 我的子弹太小了,直到我说这水平元素:

new NumberingSymbolRunProperties(
    new RunFonts() { Hint = FontTypeHintValues.Default, Ascii = "Symbol", HighAnsi = "Symbol" }) 

缩进是一个问题,直到我加入此元素的水平元素,以及:

new PreviousParagraphProperties(
    new Indentation() { Left = "864", Hanging = "360" }) 
3

如果你是喜欢我 - 从模板创建文档,然后您可能需要使用此代码来处理这两种情况 - 当您的模板包含或不包含任何编号定义时:

// Introduce bulleted numbering in case it will be needed at some point 
NumberingDefinitionsPart numberingPart = document.MainDocumentPart.NumberingDefinitionsPart; 
if (numberingPart == null) 
{ 
    numberingPart = document.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>("NumberingDefinitionsPart001"); 
} 
7

我希望能让我在文档中添加多个项目符号列表。在将我的头撞向桌面一段时间之后,我设法合并了一堆不同的帖子,并使用Open XML SDK 2检查了我的文档。0产品工具,并找出了一些东西。它生成的文档现在通过SDK生产力工具版本2.02.5的验证。

这是代码;希望它可以节省一些时间和加重。

用法:

const string fileToCreate = "C:\\temp\\bulletTest.docx"; 

if (File.Exists(fileToCreate)) 
    File.Delete(fileToCreate); 

var writer = new SimpleDocumentWriter(); 
List<string> fruitList = new List<string>() { "Apple", "Banana", "Carrot"}; 
writer.AddBulletList(fruitList); 
writer.AddParagraph("This is a spacing paragraph 1."); 

List<string> animalList = new List<string>() { "Dog", "Cat", "Bear" }; 
writer.AddBulletList(animalList); 
writer.AddParagraph("This is a spacing paragraph 2."); 

List<string> stuffList = new List<string>() { "Ball", "Wallet", "Phone" }; 
writer.AddBulletList(stuffList); 
writer.AddParagraph("Done."); 

writer.SaveToFile(fileToCreate); 

using语句:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using DocumentFormat.OpenXml; 
using DocumentFormat.OpenXml.Packaging; 
using DocumentFormat.OpenXml.Wordprocessing;  

代码

public class SimpleDocumentWriter : IDisposable 
{ 
    private MemoryStream _ms; 
    private WordprocessingDocument _wordprocessingDocument; 

    public SimpleDocumentWriter() 
    { 
     _ms = new MemoryStream(); 
     _wordprocessingDocument = WordprocessingDocument.Create(_ms, WordprocessingDocumentType.Document); 
     var mainDocumentPart = _wordprocessingDocument.AddMainDocumentPart(); 
     Body body = new Body(); 
     mainDocumentPart.Document = new Document(body); 
    } 

    public void AddParagraph(string sentence) 
    { 
     List<Run> runList = ListOfStringToRunList(new List<string> { sentence}); 
     AddParagraph(runList); 
    } 
    public void AddParagraph(List<string> sentences) 
    { 
     List<Run> runList = ListOfStringToRunList(sentences); 
     AddParagraph(runList); 
    } 

    public void AddParagraph(List<Run> runList) 
    { 
     var para = new Paragraph(); 
     foreach (Run runItem in runList) 
     { 
      para.AppendChild(runItem); 
     } 

     Body body = _wordprocessingDocument.MainDocumentPart.Document.Body; 
     body.AppendChild(para); 
    } 

    public void AddBulletList(List<string> sentences) 
    { 
     var runList = ListOfStringToRunList(sentences); 

     AddBulletList(runList); 
    } 


    public void AddBulletList(List<Run> runList) 
    { 
     // Introduce bulleted numbering in case it will be needed at some point 
     NumberingDefinitionsPart numberingPart = _wordprocessingDocument.MainDocumentPart.NumberingDefinitionsPart; 
     if (numberingPart == null) 
     { 
      numberingPart = _wordprocessingDocument.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>("NumberingDefinitionsPart001"); 
      Numbering element = new Numbering(); 
      element.Save(numberingPart); 
     } 

     // Insert an AbstractNum into the numbering part numbering list. The order seems to matter or it will not pass the 
     // Open XML SDK Productity Tools validation test. AbstractNum comes first and then NumberingInstance and we want to 
     // insert this AFTER the last AbstractNum and BEFORE the first NumberingInstance or we will get a validation error. 
     var abstractNumberId = numberingPart.Numbering.Elements<AbstractNum>().Count() + 1; 
     var abstractLevel = new Level(new NumberingFormat() {Val = NumberFormatValues.Bullet}, new LevelText() {Val = "·"}) {LevelIndex = 0}; 
     var abstractNum1 = new AbstractNum(abstractLevel) {AbstractNumberId = abstractNumberId}; 

     if (abstractNumberId == 1) 
     { 
      numberingPart.Numbering.Append(abstractNum1); 
     } 
     else 
     { 
      AbstractNum lastAbstractNum = numberingPart.Numbering.Elements<AbstractNum>().Last(); 
      numberingPart.Numbering.InsertAfter(abstractNum1, lastAbstractNum); 
     } 

     // Insert an NumberingInstance into the numbering part numbering list. The order seems to matter or it will not pass the 
     // Open XML SDK Productity Tools validation test. AbstractNum comes first and then NumberingInstance and we want to 
     // insert this AFTER the last NumberingInstance and AFTER all the AbstractNum entries or we will get a validation error. 
     var numberId = numberingPart.Numbering.Elements<NumberingInstance>().Count() + 1; 
     NumberingInstance numberingInstance1 = new NumberingInstance() {NumberID = numberId}; 
     AbstractNumId abstractNumId1 = new AbstractNumId() {Val = abstractNumberId}; 
     numberingInstance1.Append(abstractNumId1); 

     if (numberId == 1) 
     { 
      numberingPart.Numbering.Append(numberingInstance1); 
     } 
     else 
     { 
      var lastNumberingInstance = numberingPart.Numbering.Elements<NumberingInstance>().Last(); 
      numberingPart.Numbering.InsertAfter(numberingInstance1, lastNumberingInstance); 
     } 

     Body body = _wordprocessingDocument.MainDocumentPart.Document.Body; 

     foreach (Run runItem in runList) 
     { 
      // Create items for paragraph properties 
      var numberingProperties = new NumberingProperties(new NumberingLevelReference() {Val = 0}, new NumberingId() {Val = numberId}); 
      var spacingBetweenLines1 = new SpacingBetweenLines() { After = "0" }; // Get rid of space between bullets 
      var indentation = new Indentation() { Left = "720", Hanging = "360" }; // correct indentation 

      ParagraphMarkRunProperties paragraphMarkRunProperties1 = new ParagraphMarkRunProperties(); 
      RunFonts runFonts1 = new RunFonts() { Ascii = "Symbol", HighAnsi = "Symbol" }; 
      paragraphMarkRunProperties1.Append(runFonts1); 

      // create paragraph properties 
      var paragraphProperties = new ParagraphProperties(numberingProperties, spacingBetweenLines1, indentation, paragraphMarkRunProperties1); 

      // Create paragraph 
      var newPara = new Paragraph(paragraphProperties); 

      // Add run to the paragraph 
      newPara.AppendChild(runItem); 

      // Add one bullet item to the body 
      body.AppendChild(newPara); 
     } 
    } 


    public void Dispose() 
    { 
     CloseAndDisposeOfDocument(); 
     if (_ms != null) 
     { 
      _ms.Dispose(); 
      _ms = null; 
     } 
    } 

    public MemoryStream SaveToStream() 
    { 
     _ms.Position = 0; 
     return _ms; 
    } 

    public void SaveToFile(string fileName) 
    { 
     if (_wordprocessingDocument != null) 
     { 
      CloseAndDisposeOfDocument(); 
     } 

     if (_ms == null) 
      throw new ArgumentException("This object has already been disposed of so you cannot save it!"); 

     using (var fs = File.Create(fileName)) 
     { 
      _ms.WriteTo(fs); 
     } 
    } 

    private void CloseAndDisposeOfDocument() 
    { 
     if (_wordprocessingDocument != null) 
     { 
      _wordprocessingDocument.Close(); 
      _wordprocessingDocument.Dispose(); 
      _wordprocessingDocument = null; 
     } 
    } 

    private static List<Run> ListOfStringToRunList(List<string> sentences) 
    { 
     var runList = new List<Run>(); 
     foreach (string item in sentences) 
     { 
      var newRun = new Run(); 
      newRun.AppendChild(new Text(item)); 
      runList.Add(newRun); 
     } 

     return runList; 
    } 
} 
+0

非常感谢你为我展示如何将列表添加到文档中。我使用Numbering.Append(abstactNum,numberingInstance),并不明白为什么它不起作用 – Dan 2017-11-17 08:51:31

+0

从未来:谢谢你的队友!真的! :) – 2018-03-08 15:08:33

+0

@MariusConjeaud不客气。我创建了一些用于编写简单的文档的文档,欢迎使用(请参阅https://github.com/madcodemonkey/SimpleDocument.OpenXML) – 2018-03-10 00:12:13

相关问题