いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-469 (複数のdocxファイルをマージする)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

実務やってると、たまに設計書を各章ごとにバラバラにして管理しているプロジェクトもあったりします。

で、最終的にマージしてお客様に納品するという感じですね。

ですが、マージ前を閲覧して作業しないといけない側からすると、特定の仕様がどこに書かれているのかを探すのがとても面倒。。

なので、全部結合してしまえばよいのですが、数個であれば手動でできますが、十数個とかに分割されていたらもう面倒の極みです。

結合するプログラムなんて、何でも良いのですが、ついでなのでGoでやってみました。

てことで、Goでdocxファイルを結合するプログラムをちょっと書いたので、メモ代わりにここに置いておきます。

サンプル

package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "path/filepath"
    "strings"

    "github.com/devlights/gord"
    "github.com/devlights/gord/constants"
)

type (
    Args struct {
        dir string
        out string
    }
)

var (
    args Args
)

var (
    appLog = log.New(os.Stdout, ">>> ", 0)
)

func init() {
    flag.StringVar(&args.dir, "dir", ".", "directory")
    flag.StringVar(&args.out, "out", "result.docx", "output file path")
}

func main() {
    flag.Parse()

    if args.dir == "" {
        args.dir = "."
    }

    if args.out == "" {
        args.out = "result.docx"
    }

    if err := run(); err != nil {
        log.Fatal(err)
    }

    appLog.Println("done")
}

func abs(p string) string {
    v, _ := filepath.Abs(p)
    return v
}

func genErr(procName string, err error) error {
    return fmt.Errorf("%s failed: %w", procName, err)
}

func run() error {
    quit, _ := gord.InitGord()
    defer quit()

    word, wordRelease, _ := gord.NewGord()
    defer wordRelease()

    _ = word.Silent(false)

    docs, err := word.Documents()
    if err != nil {
        return genErr("word.Documents()", err)
    }

    newDoc, docRelease, err := docs.Add()
    if err != nil {
        return genErr("docs.Add()", err)
    }
    defer docRelease()

    err = filepath.WalkDir(abs(args.dir), func(path string, d os.DirEntry, err error) error {
        if err != nil {
            return err
        }

        if d.IsDir() {
            return nil
        }

        if !strings.HasSuffix(path, ".docx") {
            return nil
        }

        // ドキュメントの最後に移動
        nr, err := newDoc.AllRange()
        if err != nil {
            return genErr("newDoc.AllRange()", err)
        }

        err = nr.Collapse(constants.WdCollapseDirectionEnd)
        if err != nil {
            return genErr("nr.Collapse()", err)
        }

        // ファイルを挿入
        absPath := abs(path)
        err = nr.InsertFile(absPath)
        if err != nil {
            return genErr("nr.InsertFile()", err)
        }

        appLog.Printf("MERGE : %s", absPath)

        return nil
    })

    if err != nil {
        return err
    }

    // 保存
    err = newDoc.SaveAsWithFileFormatDefault(abs(args.out))
    if err != nil {
        return genErr("newDoc.SaveAs2()", err)
    }

    return nil
}

以下のようにして利用します。

$ go build -o merge-docx.exe .
$ ./merge-docx.exe -dir /path/to/documents

指定したディレクトリ配下の docx ファイルを結合します。テンプレートとかでガチガチにレイアウトを仕込んでいるドキュメントの場合は多分キレイにマージ出来ないと思いますが、単純なドキュメントなら良い感じに結合されると思います。

参考情報

GitHub - devlights/gord: Gord is a library to operate MS Word using go-ole library.

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。