Main
go
package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
gotemplatedocx "github.com/JJJJJJack/go-template-docx"
)
const (
VERSION = "v1.4.6"
)
var USAGE = fmt.Sprintf("\nUsage: %s <file.docx> <values.json> [<values2.json> ...]\n\nThe output files will have the filename of the json file they are generated from (values.docx, values2.docx ...)\n%s", filepath.Base(os.Args[0]),
`
optional flags:
-h, --help: show this help message and exit
--version: show go-template-docx version and exit
--verbose: enable verbose error messages
-i <image.jpg|png>: load an image from disk
(you can use multiple -i flags, make sure the filenames are unique)
`)
func filenameStartIndex(path string) int {
start := strings.LastIndex(path, "/")
if start == -1 {
start = strings.LastIndex(path, "\\")
}
return start
}
func main() {
if len(os.Args) < 3 {
fmt.Print(USAGE)
return
}
docxFilepath := os.Args[1]
jsonFilenames := []string{}
for _, arg := range os.Args[2:] {
if !strings.HasSuffix(arg, ".json") {
break
}
jsonFilenames = append(jsonFilenames, arg)
}
flags := make(map[string]bool)
for _, arg := range os.Args {
if !strings.HasPrefix(arg, "-") {
continue
}
switch arg {
case "-h", "--help":
fmt.Print(USAGE)
return
case "--version":
fmt.Println(VERSION)
return
case "--verbose", "-v":
flags["verbose"] = true
case "-i":
default:
fmt.Printf("Unknown flag: %s\n", arg)
return
}
}
images := make([]string, 0, ((len(os.Args)-3)/2)+1)
for i, arg := range os.Args {
if arg != "-i" {
continue
}
if i+1 >= len(os.Args) {
fmt.Println("Error: -i flag provided but no image file specified")
return
}
images = append(images, os.Args[i+1])
}
for _, jsonFilepath := range jsonFilenames {
jsonFilename := jsonFilepath[filenameStartIndex(jsonFilepath)+1 : strings.LastIndex(jsonFilepath, ".")]
docxFilename := docxFilepath[filenameStartIndex(docxFilepath)+1 : strings.LastIndex(docxFilepath, ".")]
if jsonFilename == docxFilename {
fmt.Printf("The file JSON %s have the same filename as the docx template file, this could result in overwriting the template file, use unique filenames\n", jsonFilepath)
return
}
jsonBytes, err := os.ReadFile(jsonFilepath)
if err != nil {
fmt.Println("Error reading JSON file:", err)
return
}
templateValues := any(nil)
err = json.Unmarshal(jsonBytes, &templateValues)
if err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return
}
docxTemplate, err := gotemplatedocx.NewDocxTemplateFromFilename(docxFilepath)
if err != nil {
fmt.Println("Error creating template:", err)
return
}
for _, image := range images {
imageData, err := os.ReadFile(image)
if err != nil {
fmt.Println("Error reading image file:", err)
return
}
docxTemplate.Media(image, imageData)
}
err = docxTemplate.Apply(templateValues)
if err != nil {
if !flags["verbose"] {
deepestErr := errors.Unwrap(err)
for deepestErr != nil {
err = deepestErr
deepestErr = errors.Unwrap(err)
}
}
fmt.Println("Error applying template:", err)
return
}
start := strings.LastIndex(jsonFilepath, "/")
if start == -1 {
start = strings.LastIndex(jsonFilepath, "\\")
}
filename := jsonFilepath[start+1:strings.LastIndex(jsonFilepath, ".")] + ".docx"
err = docxTemplate.Save(filename)
if err != nil {
fmt.Println("Error saving docx:", err)
return
}
}
}