OpenXML 2 SDK - Word 문서 - 프로그래밍 방식으로 글머리 기호 목록 만들기

StackOverflow https://stackoverflow.com/questions/1940911

문제

OpenXML SDK, 2.0 CTP를 사용하여 프로그래밍 방식으로 Word 문서를 만들려고 합니다.내 문서에 글머리 기호 목록을 삽입해야 하며 목록의 일부 요소에 밑줄을 그어야 합니다.어떻게 해야 하나요?

도움이 되었습니까?

해결책

OpenXML의 목록은 약간 혼란 스럽습니다.

이있다 NumberingDefinitionSpart 문서의 모든 목록을 설명합니다. 목록이 나타나는 방법 (총알, 번호가 매겨진 등)에 대한 정보가 포함되어 있으며 각각에도 할당 및 ID도 포함됩니다.

그런 다음 MainDocumentPart, 작성하려는 목록의 모든 항목에 대해 새 단락을 추가하고 해당 단락에 원하는 목록의 ID를 할당합니다.

따라서 다음과 같은 총알 목록을 작성하려면 다음과 같습니다.

  • 안녕하십니까,
  • 세계!

먼저 번호 definitionspart를 만들어야합니다.

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

그런 다음 단락 속성을 제외하고는 Numbering ID를 할당하는 MainDocumentPart를 평소와 같이 만듭니다.

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 참조 안내서 섹션 2.9에서.

다른 팁

문서에 총알 목록이 하나 이상 추가 될 수있는 무언가를 원했습니다. 한동안 책상에 머리를 두드린 후, 나는 다양한 게시물을 결합하고 내 문서를 열린 XML SDK 2.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;
    }
}

위의 Adam의 답변은 새로운 NumberingInstance를 제외하고는 (New Nums 대신에 언급 된 바와 같이) 정확히 정확합니다.

또한 여러 목록이있는 경우 여러 개의 번호 요소가 있어야합니다 (각각 자체 ID 1, 2, 3 등이 있어야합니다. 문서의 각 목록마다 하나씩. 이것은 총알 목록에 문제가되지 않는 것 같습니다. 그러나 번호가 매겨진 목록은 동일한 번호 순서를 계속 사용하여 (1에서 다시 시작하는 것과 달리)는 동일한 목록이라고 생각할 것이기 때문에 다음과 같은 단락에서 참조해야합니다.

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

레벨 요소의 어린이는 총알의 유형과 들여 쓰기에 영향을 미칩니다. 내가 이것을 레벨 요소에 추가 할 때까지 내 총알이 너무 작았습니다.

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

이 요소가 레벨 요소에도 추가 할 때까지 들여 쓰기는 문제였습니다.

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

그리고 당신이 나와 같다면 템플릿에서 문서를 생성하는 경우 이 코드를 사용하여 템플릿에 번호 매기기 정의가 포함되거나 포함되지 않는 두 가지 상황을 모두 처리할 수 있습니다.

// 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");
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top