web-dev-qa-db-ja.com

複数のWordドキュメントを1つのOpen Xmlにマージする

私は、open xmlやその他のものを使用して生成した約10のWordドキュメントを持っています。次に、別のWord文書を作成し、1つずつこの新しく作成された文書に結合します。私はオープンxmlを使用したいのですが、どんなヒントでもあります。以下は私のコードです:

 private void CreateSampleWordDocument()
    {
        //string sourceFile = Path.Combine("D:\\GeneralLetter.dot");
        //string destinationFile = Path.Combine("D:\\New.doc");
        string sourceFile = Path.Combine("D:\\GeneralWelcomeLetter.docx");
        string destinationFile = Path.Combine("D:\\New.docx");
        try
        {
            // Create a copy of the template file and open the copy
            //File.Copy(sourceFile, destinationFile, true);
            using (WordprocessingDocument document = WordprocessingDocument.Open(destinationFile, true))
            {
                // Change the document type to Document
                document.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                //Get the Main Part of the document
                MainDocumentPart mainPart = document.MainDocumentPart;
                mainPart.Document.Save();
            }
        }
        catch
        {
        }
    }

pdate(AltChunksを使用):

using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true))
        {
            string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2) ;
            MainDocumentPart mainPart = myDoc.MainDocumentPart;
            AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(
                AlternativeFormatImportPartType.WordprocessingML, altChunkId);
            using (FileStream fileStream = File.Open("D:\\Test1.docx", FileMode.Open))
                chunk.FeedData(fileStream);
            AltChunk altChunk = new AltChunk();
            altChunk.Id = altChunkId;
            mainPart.Document
                .Body
                .InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
            mainPart.Document.Save();
        } 

複数のファイルを使用すると、なぜこのコードが最後のファイルの内容を上書きするのですか? 更新2:

 using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true))
        {

            MainDocumentPart mainPart = myDoc.MainDocumentPart;
            string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 3);
            AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
            using (FileStream fileStream = File.Open("d:\\Test1.docx", FileMode.Open))
            {
                chunk.FeedData(fileStream);
                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                mainPart.Document
                    .Body
                    .InsertAfter(altChunk, mainPart.Document.Body
                    .Elements<Paragraph>().Last());
                mainPart.Document.Save();
            }
            using (FileStream fileStream = File.Open("d:\\Test2.docx", FileMode.Open))
            {
                chunk.FeedData(fileStream);
                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                mainPart.Document
                    .Body
                    .InsertAfter(altChunk, mainPart.Document.Body
                    .Elements<Paragraph>().Last());
            }
            using (FileStream fileStream = File.Open("d:\\Test3.docx", FileMode.Open))
            {
                chunk.FeedData(fileStream);
                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                mainPart.Document
                    .Body
                    .InsertAfter(altChunk, mainPart.Document.Body
                    .Elements<Paragraph>().Last());
            } 
        }

このコードは、Test1データの代わりにTest2データを2回追加しています。私が得る手段:

Test
Test2
Test2

の代わりに :

Test
Test1
Test2
21
JulyOrdinary

OpenXML SDKのみを使用して、 AltChunk 要素を使用して複数のドキュメントを1つにマージできます。

このリンク the-easy-way-to-assemble-multiple-Word-documents およびこのリンク ドキュメントのアセンブリにaltChunkを使用する方法 はいくつかのサンプルを提供します。

EDIT 1

更新された質問(update#1)altchunkを使用するコードに基づいて、私がテストしたVB.Netコードは次のとおりで、これは魅力的なように機能します私のために:

_Using myDoc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open("D:\\Test.docx", True)
        Dim altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2)
        Dim mainPart = myDoc.MainDocumentPart
        Dim chunk = mainPart.AddAlternativeFormatImportPart(
            DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML, altChunkId)
        Using fileStream As IO.FileStream = IO.File.Open("D:\\Test1.docx", IO.FileMode.Open)
            chunk.FeedData(fileStream)
        End Using
        Dim altChunk = New DocumentFormat.OpenXml.Wordprocessing.AltChunk()
        altChunk.Id = altChunkId
        mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements(Of DocumentFormat.OpenXml.Wordprocessing.Paragraph).Last())
        mainPart.Document.Save()
End Using
_

EDIT 2

2番目の問題(update#2)

このコードは、Test1データの代わりにTest2データを2回追加しています。

altchunkidに関連しています。

メインドキュメントにマージするドキュメントごとに、次のことを行う必要があります。

  1. AlternativeFormatImportPartmainDocumentPartを追加し、Idを追加します。これは一意でなければなりません。この要素挿入されたデータが含まれています
  2. 前のAltchunkを参照するようにidを設定するAlternativeFormatImportPart要素を本文に追加します。

コードでは、すべてのAltChunksに同じIDを使用しています。そのため、同じテキストが何度も表示されます。

Altchunkidがあなたのコードで一意になるかわかりません:string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

特定の値を設定する必要がない場合は、AltChunkIdを追加するときにAlternativeFormatImportPartを明示的に設定しないことをお勧めします。代わりに、次のようにSDKによって生成されます。

VB.Net

_Dim chunk As AlternativeFormatImportPart = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML)
Dim altchunkid As String = mainPart.GetIdOfPart(chunk)
_

C#

_AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML);
string altchunkid = mainPart.GetIdOfPart(chunk);
_
20
Chris

文書をマージするために特別に設計されたopen xmlの周りにはニースラッパーAPI(ドキュメントビルダー2.2)があり、マージする段落を選択するなどの柔軟性があります。これは here (update:move to- github )。

それの使い方に関するドキュメントとスクリーンキャストは here です。

更新:コードサンプル

 var sources = new List<Source>();
 //Document Streams (File Streams) of the documents to be merged.
 foreach (var stream in documentstreams)
 {
        var tempms = new MemoryStream();
        stream.CopyTo(tempms);
        sources.Add(new Source(new WmlDocument(stream.Length.ToString(), tempms), true));
 }

  var mergedDoc = DocumentBuilder.BuildDocument(sources);
  mergedDoc.SaveAs(@"C:\TargetFilePath");

タイプSourceおよびWmlDocumentは、Document Builder APIからのものです。

次のように選択した場合は、ファイルパスを直接追加することもできます。

sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged1.docx"));
sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged2.docx"));

これが見つかりました 素敵な比較AltChunkDocument Builderの間でドキュメントをマージする方法-要件に基づいて選択すると役立ちます。

DocX ライブラリを使用してドキュメントをマージすることもできますが、ドキュメントのマージには、これよりもドキュメントビルダーの方が適しています。

お役に立てれば。

9
Flowerking

C#で使いやすい:

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

namespace WordMergeProject
{
    public class Program
    {
        private static void Main(string[] args)
        {
            byte[] Word1 = File.ReadAllBytes(@"..\..\Word1.docx");
            byte[] Word2 = File.ReadAllBytes(@"..\..\Word2.docx");

            byte[] result = Merge(Word1, Word2);

            File.WriteAllBytes(@"..\..\Word3.docx", result);
        }

        private static byte[] Merge(byte[] dest, byte[] src)
        {
            string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString();

            var memoryStreamDest = new MemoryStream();
            memoryStreamDest.Write(dest, 0, dest.Length);
            memoryStreamDest.Seek(0, SeekOrigin.Begin);
            var memoryStreamSrc = new MemoryStream(src);

            using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStreamDest, true))
            {
                MainDocumentPart mainPart = doc.MainDocumentPart;
                AlternativeFormatImportPart altPart =
                    mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
                altPart.FeedData(memoryStreamSrc);
                var altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                              OpenXmlElement lastElem = mainPart.Document.Body.Elements<AltChunk>().LastOrDefault();
            if(lastElem == null)
            {
                lastElem = mainPart.Document.Body.Elements<Paragraph>().Last();
            }


            //Page Brake einfügen
            Paragraph pageBreakP = new Paragraph();
            Run pageBreakR = new Run();
            Break pageBreakBr = new Break() { Type = BreakValues.Page };

            pageBreakP.Append(pageBreakR);
            pageBreakR.Append(pageBreakBr);                

            return memoryStreamDest.ToArray();
        }
    }
}
3
yonexbat

これらの回答に欠けている唯一のものは、forループです。

単にコピー/貼り付けしたい人のために:

void MergeInNewFile(string resultFile, IList<string> filenames)
{
    using (WordprocessingDocument document = WordprocessingDocument.Create(resultFile, WordprocessingDocumentType.Document))
    {
        MainDocumentPart mainPart = document.AddMainDocumentPart();
        mainPart.Document = new Document(new Body());

        foreach (string filename in filenames)
        {
            AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML);
            string altChunkId = mainPart.GetIdOfPart(chunk);

            using (FileStream fileStream = File.Open(filename, FileMode.Open))
            {
                chunk.FeedData(fileStream);
            }

            AltChunk altChunk = new AltChunk { Id = altChunkId };
            mainPart.Document.Body.AppendChild(altChunk);
        }

        mainPart.Document.Save();
    }
}

すべてのクレジットはChrisとyonexbatに送られます

1
Jinjinov