diff --git a/docx_comment.go b/docx_comment.go
index c50a8a8..fff06cf 100644
--- a/docx_comment.go
+++ b/docx_comment.go
@@ -65,6 +65,7 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
}
used := make([]bool, len(comments))
+ applied := make([]DocxComment, 0, len(comments))
id := 0
newDoc := docxParaRe.ReplaceAllStringFunc(string(doc), func(p string) string {
txt := docxPlain(p)
@@ -73,6 +74,9 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
continue
}
used[i] = true
+ // Record in document order so comments.xml id N matches the marker
+ // with id N (the spec order may differ from the document order).
+ applied = append(applied, c)
p = docxAddMarkers(p, id)
id++
break
@@ -80,12 +84,6 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
return p
})
- applied := make([]DocxComment, 0, len(comments))
- for i, c := range comments {
- if used[i] {
- applied = append(applied, c)
- }
- }
parts["word/document.xml"] = []byte(newDoc)
parts["word/comments.xml"] = docxBuildComments(author, applied)
parts["[Content_Types].xml"] = docxAddContentType(parts["[Content_Types].xml"])
diff --git a/docx_comment_test.go b/docx_comment_test.go
index 399f3b0..d9d730f 100644
--- a/docx_comment_test.go
+++ b/docx_comment_test.go
@@ -4,6 +4,7 @@ import (
"archive/zip"
"bytes"
"io"
+ "regexp"
"strings"
"testing"
)
@@ -124,6 +125,48 @@ func TestInjectDocxCommentsNoMatch(t *testing.T) {
}
}
+// TestInjectDocxCommentsOrder guards the marker-id ↔ comments.xml pairing when
+// the spec order differs from the document order.
+func TestInjectDocxCommentsOrder(t *testing.T) {
+ src := buildTestDocx(t)
+ spec := []DocxComment{
+ {Anchor: "Nothing relevant", Text: "comment B"},
+ {Anchor: "The term is two years", Text: "comment A"},
+ }
+ out, applied, err := InjectDocxComments(src, "A", spec)
+ if err != nil || applied != 2 {
+ t.Fatalf("inject: applied=%d err=%v", applied, err)
+ }
+ doc := unzipPart(t, out, "word/document.xml")
+ cmts := unzipPart(t, out, "word/comments.xml")
+
+ // id -> text from comments.xml
+ byID := map[string]string{}
+ for _, m := range regexp.MustCompile(`(?s)]*>(.*?)`).FindAllStringSubmatch(cmts, -1) {
+ txt := strings.TrimSpace(stripTags(m[2]))
+ byID[m[1]] = txt
+ }
+ // paragraph that starts with the term text must point at "comment A"
+ for _, p := range regexp.MustCompile(`(?s)]*>.*?`).FindAllString(doc, -1) {
+ if !strings.Contains(stripTags(p), "The term is two years") {
+ continue
+ }
+ m := regexp.MustCompile(``).FindStringSubmatch(p)
+ if m == nil {
+ t.Fatal("no commentRangeStart in the term paragraph")
+ }
+ if got := byID[m[1]]; got != "comment A" {
+ t.Fatalf("term paragraph points at id %s = %q, want \"comment A\"", m[1], got)
+ }
+ return
+ }
+ t.Fatal("term paragraph not found")
+}
+
+func stripTags(s string) string {
+ return regexp.MustCompile(`<[^>]*>`).ReplaceAllString(s, "")
+}
+
func TestParseDocxComments(t *testing.T) {
got, err := ParseDocxComments([]byte(`[{"anchor":"a","text":"b"}]`))
if err != nil {