代码之家  ›  专栏  ›  技术社区  ›  kjv

openxml 2 sdk-word文档-以编程方式创建项目符号列表

  •  14
  • kjv  · 技术社区  · 15 年前

    使用openxml sdk,2.0ctp,我试图以编程方式创建一个word文档。在我的文档中,我必须插入一个项目符号列表,列表中的某些元素必须加下划线。我该怎么做?

    4 回复  |  直到 7 年前
        1
  •  27
  •   Adam Sheehan    9 年前

    openxml中的列表有点混乱。

    有一个 数字定义 描述文档中所有列表的。它包含有关列表应如何显示的信息(项目符号、编号等),还为每个列表分配和标识。

    然后在 主文档部件 ,对于要创建的列表中的每个项,您将添加一个新段落并将列表的ID分配给该段落。

    因此,要创建项目符号列表,例如:

    • 你好,
    • 世界!

    首先必须创建一个数字定义:

    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);
    

    OpenXML reference guide 在第2.9节中。

        2
  •  12
  •   Jonathan Sayce    7 年前

    我想要一些能让我在一个文档中添加多个项目符号列表的东西。在我的头撞在桌子上一段时间后,我设法组合了一堆不同的帖子,并用openxmlsdk2.0产品工具检查了我的文档,找出了一些东西。它生成的文档现在通过了按版本的验证 2.0 2.5 sdk生产力工具。

    这里是代码;希望它能节省一些时间和恼怒的人。

    使用:

    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 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;
        }
    }
    
        3
  •  5
  •   bonifaceviii    11 年前

    亚当上面的回答是正确的,只是它是newnumeringinstance(而不是new 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元素的子元素将影响项目符号的类型和缩进。 我的子弹太小了,直到我将其添加到level元素:

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

    在我将此元素添加到level元素之前,缩进也是一个问题:

    new PreviousParagraphProperties(
      new Indentation() { Left = "864", Hanging = "360" })
    
        4
  •  4
  •   ajeh    10 年前

    如果您和我一样-使用模板创建文档,那么您可能希望使用此代码来处理这两种情况-当您的模板包含或不包含任何编号定义时:

    // 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");
    }