R 和 Microsoft Word:根据另一个 Word 文档中的文本更新一个 Word 文档中的文本

R and Microsoft Word: Updating text in one Word document based on text in another Word document

我的问题的更新版本。下面是生成两个 Word 文档的代码。第一个文档包含一系列 table 标题,每个标题都带有书签。第二个文档包含一个实际的 table。

我希望能够根据第一个文档中指定的内容来确定第二个文档中的 table 标题应该是什么。我相信这样做的机制可能涉及在第一个文档中找到相关的书签,向上移动一行到实际标题所在的位置,然后复制标题,以便它可以在第二个文档中使用。

library(officer)
library(magrittr)
library(flextable)

read_docx() %>%

body_add_par(value = "Fred Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "FredBMK") %>%
body_add_par("") %>%

body_add_par(value = "Sally Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "SallyBMK") %>%
body_add_par("") %>%               

body_add_par(value = "George Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "GeorgeBMK") %>%
body_add_par("") %>%                               

body_add_par(value = "Sample Data from the mtcars Dataset", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "mtcarsBMK") %>%
body_add_par("") %>%                                               

body_add_par(value = "Susan Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "SusanBMK") %>%
body_add_par("") %>%                               

print(target = "Test Report Skeleton.docx")


read_docx() %>%
body_add_par(value = "Table Title (Corresponding to mtcarsBMK) from Other Document Goes Here", style = "table title") %>%
body_add_par("") %>%
body_add_flextable(flextable(mtcars[1:12, 1:3])) %>%
print(target = "Test Target Table.docx")

原问题:

我正在使用 R officer 包生成 Word 文档。想象一个场景,文本最初在两个 word 文档中同步。一个是较大的报告,另一个是生成然后自动插入到报告中的 table。 table 的标题在两个文档中的开头相同。现在假设医学作家手动更改报告中 table 的标题。我希望能够检测到这一点,然后自动更新 table 中的标题,使其与报告中的内容相匹配。

officer 包文档展示了如何用用户指定的文本字符串替换单个文档中的文本。我不清楚它是否可以用来完成我想要完成的事情。我也不清楚这不能在官员内部完成。

下面是一些制作两个word文档的代码。一个表示对 table 标题进行了更改的报告。另一个代表需要更新标题以匹配报告的原始 table。差异很小。一个标题中的单词全部大写,而另一个标题中没有。

我希望有人清楚如何检测第一个文档中的更改,然后更新第二个文档中的标题。

library(officer)
library(magrittr)

read_docx() %>%
body_add_par(value = "AWESOME Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "AwesomeBMK") %>%
body_add_par("(Awesome table appears here immediately after AwesomeBMK bookmark)") %>%
print(target = "Awesome Report.docx")

read_docx() %>%
body_add_par(value = "Awesome Table", style = "table title") %>%
body_add_par("") %>%
body_bookmark(id = "AwesomeBMK") %>%
body_add_par("(Awesome table appears here immediately after AwesomeBMK bookmark)") %>%
print(target = "Awesome Table.docx")

我不完全确定要更改哪个文档是正确的,希望能提供流程图以更好地遵循您的工作流程。

对于我的解决方案,首先我创建您的文档并保存路径以便稍后阅读。 (您应该稍后从您的目录中阅读它们)。 比起我用 docx_summary() 阅读 docx,比较两个文档并寻找更改。您不能使用此代码更改多个更改,但应该是可行的。 最后,我使用 officer 函数来替换文本。

library(officer)
library(magrittr)

doc_copy <- read_docx() %>%
  body_add_par(value = "AWESOME Table", style = "table title") %>%
  body_add_par("") %>%
  body_bookmark(id = "AwesomeBMK") %>%
  body_add_par("(Awesome table appears here immediately after AwesomeBMK bookmark)") %>%
  print(target = "Awesome Report.docx")

doc_orginal <- read_docx() %>%
  body_add_par(value = "Awesome Table", style = "table title") %>%
  body_add_par("") %>%
  body_bookmark(id = "AwesomeBMK") %>%
  body_add_par("(Awesome table appears here immediately after AwesomeBMK bookmark)") %>%
  print(target = "Awesome Table.docx")


#detect change
doc_copy_summary <- read_docx(doc_copy) %>%
  docx_summary()

doc_orginal_summary <- read_docx(doc_orginal) %>%
  docx_summary()

test <- as.data.frame(doc_copy_summary == doc_orginal_summary)

old <- doc_orginal_summary[which(test==F, arr.ind = T)]
change <- doc_copy_summary[which(test==F, arr.ind = T)]

#instert text
my_doc <- read_docx(doc_orginal)  %>% 
  cursor_reach(keyword = paste0(old)) %>% 
  body_add_par(value = paste0(change), pos = "on")%>%
  print(target = "Change Awesome Table.docx")

以下是我认为的解决方案。我对 XML 的了解还处于初级阶段。认为这是可行的。

代码的第一部分制作了一个 Word 文件。第二部分使该文件下的 XML 可访问。第三部分阅读XML的相关部分。第五部分捕获 table 和紧跟书签的图形标题。第六部分捕获紧接 table 或图形标题前面的书签。 Word file/XML 中有一个 table 标题和一个书签不匹配。 table 标题不匹配,因为后面没有书签。书签不匹配,因为之前没有 table 或图形标题。最后一部分将 table/figure 标题链接到其相应的书签。

原计划在这里也提供 XML。但决定反对它,因为任何 Word 文档的 XML 都非常冗长,并且需要永远格式化它。

尝试 运行 代码的人将没有我使用的包含 Table Title 1 和 Figure Title 1 样式的 Word 文档模板。我相信可以很容易地设计出一个 suitable Word 模板,尽管它具有自己的 table 标题和图形标题样式版本。

希望有一天这会对某人有所帮助。

#### Make Word file ####

library(officer)
library(magrittr)
library(xml2)

read_docx("Report Template Blank.docx") %>%            

body_remove() %>%
body_add_par(value = "Fred Table", style = "Table Title 1") %>%
body_add_par("") %>%
body_bookmark(id = "FredtblBMK") %>%
body_add_par("") %>%

body_add_par(value = "Fred Figure", style = "Figure Title 1") %>%
body_add_par("") %>%
body_bookmark(id = "FredfigBMK") %>%
body_add_par("") %>%

body_add_par(value = "Sally Table", style = "Table Title 1") %>%
body_add_par("") %>%
body_bookmark(id = "SallytblBMK") %>%
body_add_par("") %>%

body_add_par(value = "Sally Figure", style = "Figure Title 1") %>%
body_add_par("") %>%
body_bookmark(id = "SallyfigBMK") %>%
body_add_par("") %>%

body_add_par(value = "Unmatched Table", style = "Table Title 1") %>%
body_add_par("") %>%

body_add_par("Some text separating the unmatched title and unmatched bookmark.") %>%
body_add_par("") %>%

body_bookmark(id = "UnmatchedBMK") %>%
body_add_par("") %>%

print(target = "Test Report Skeleton.docx")

#### Make XML underlying Word document accessible ####

file.copy("Test Report Skeleton.docx", "Test Report Skeleton.zip", overwrite = TRUE)
unzip("Test Report Skeleton.zip", exdir = "Test Report Skeleton XML")

#### Read XML ####

doc <-  read_xml("./Test Report Skeleton XML/word/document.xml")

#### Find qualifying table and figure titles ####

xml_tbl <-
xml_find_all(
doc,
"//w:p[w:pPr/w:pStyle[@w:val='TableTitle1' or @w:val='FigureTitle1'] and
./following-sibling::w:p[1][./w:bookmarkStart]]"
) %>%
xml_text()

#### Find qualifying bookmarks ####

xml_bmk <-
xml_find_all(
doc,
"//w:p[./w:bookmarkStart and
./preceding-sibling::w:p[1][./w:pPr/w:pStyle[@w:val='TableTitle1' or @w:val='FigureTitle1']]]
/w:bookmarkStart"
) %>%
xml_attr("name")

xml_tbl_bmk <- data.frame(title = xml_tbl, bookmark = xml_bmk)

#### Show results ####

xml_tbl_bmk

         title    bookmark
1   Fred Table  FredtblBMK
2  Fred Figure  FredfigBMK
3  Sally Table SallytblBMK
4 Sally Figure SallyfigBMK