Skip to content

Commit

Permalink
Merge pull request #962 from thebioengineer/gt_to_word
Browse files Browse the repository at this point in the history
Gt to word
  • Loading branch information
rich-iannone authored Jul 5, 2022
2 parents 2634266 + db1c3ec commit a585bd6
Show file tree
Hide file tree
Showing 24 changed files with 4,144 additions and 118 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ tests/testthat/test-tab_options.R
tests/testthat/test-tab_spanner.R
tests/testthat/test-tab_spanner_delim.R
tests/testthat/test-table_parts.R
tests/testthat/test-as_word.R
5 changes: 4 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Authors@R: c(
person("Joe", "Cheng", , "joe@rstudio.com", "aut"),
person("Barret", "Schloerke", , "barret@rstudio.com", "aut",
comment = c(ORCID = "0000-0001-9986-114X")),
person("Ellis", "Hughes", , "ellis.h.hughes@gsk.com", "aut",
comment = c(ORCID = "0000-0003-0637-4436")),
person("RStudio", role = c("cph", "fnd"))
)
License: MIT + file LICENSE
Expand Down Expand Up @@ -111,10 +113,11 @@ Collate:
'utils_general_str_formatting.R'
'utils_pipe.R'
'utils_render_common.R'
'utils_render_footnotes.R'
'utils_render_html.R'
'utils_render_latex.R'
'utils_render_rtf.R'
'utils_render_xml.R'
'z_utils_render_footnotes.R'
'zzz.R'
Config/testthat/edition: 3
Config/testthat/parallel: true
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export(adjust_luminance)
export(as_latex)
export(as_raw_html)
export(as_rtf)
export(as_word)
export(cell_borders)
export(cell_fill)
export(cell_text)
Expand Down Expand Up @@ -121,6 +122,7 @@ importFrom(dplyr,vars)
importFrom(ggplot2,ggsave)
importFrom(htmltools,css)
importFrom(magrittr,"%>%")
importFrom(rlang,`%||%`)
importFrom(tidyselect,contains)
importFrom(tidyselect,ends_with)
importFrom(tidyselect,everything)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# gt (development version)

* word table output via `as_word()`. (#929)

# gt 0.6.0

## New features
Expand Down
176 changes: 175 additions & 1 deletion R/export.R
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,180 @@ as_rtf <- function(data) {
rtf_table
}

#' Output a **gt** object as Word
#'
#' @description
#' Get the Open Office XML table tag content from a `gt_tbl` object as as a
#' single-element character vector.
#'
#' @param data A table object that is created using the `gt()` function.
#' @param align left, center (default) or right.
#' @param caption_location top (default), bottom, or embed Indicating if the
#' title and subtitle should be listed above, below, or be embedded in the
#' table
#' @param caption_align left (default), center, or right. Alignment of caption
#' (title and subtitle). Used when `caption_location` is not "embed".
#' @param split TRUE or FALSE (default) indicating whether activate Word option
#' 'Allow row to break across pages'.
#' @param keep_with_next TRUE (default) or FALSE indicating whether a table
#' should use Word option 'keep rows together' is activated when TRUEd
#'
#' @examples
#' # Use `gtcars` to create a gt table;
#' # add a header and then export as
#' # OOXML code for Word
#' tab_rtf <-
#' gtcars %>%
#' dplyr::select(mfr, model) %>%
#' dplyr::slice(1:2) %>%
#' gt() %>%
#' tab_header(
#' title = md("Data listing from **gtcars**"),
#' subtitle = md("`gtcars` is an R dataset")
#' ) %>%
#' as_word()
#'
#' @family Export Functions
#' @section Function ID:
#' 13-5
#'
#' @export
as_word <- function(
data,
align = "center",
caption_location = c("top","bottom","embed"),
caption_align = "left",
split = FALSE,
keep_with_next = TRUE
) {

# Perform input object validation
stop_if_not_gt(data = data)
caption_location <- match.arg(caption_location)

# Build all table data objects through a common pipeline
value <- build_data(data = data, context = "word")

gt_xml <- c()

# Composition of Word table OOXML -----------------------------------------------
if (caption_location %in% c("top")) {
header_xml <- as_word_tbl_header_caption(data = value, align = caption_align, split = split, keep_with_next = keep_with_next)
gt_xml <- c(gt_xml, header_xml)
}

tbl_xml <- as_word_tbl_body(data = value, align = align, split = split, keep_with_next = keep_with_next, embedded_heading = identical(caption_location, "embed"))
gt_xml <- c(gt_xml, tbl_xml)


if (caption_location %in% c("bottom")) {
## set keep_with_next to false here to prevent it trying to keep with non-table content
header_xml <- as_word_tbl_header_caption(data = value, align = caption_align, split = split, keep_with_next = FALSE)
gt_xml <- c(gt_xml, header_xml)
}

gt_xml <- paste0(gt_xml, collapse = "")

gt_xml

}

#' Generate ooxml for the table caption
#'
#' @param data A processed table object that is created using the `build_data()` function.
#' @param align left (default), center or right.
#' @param split TRUE or FALSE (default) indicating whether activate Word option 'Allow row to break across pages'.
#' @param keep_with_next TRUE (default) or FALSE indicating whether a table should use Word option 'keep rows
#' together' is activated when TRUE
#'
#' @noRd
as_word_tbl_header_caption <- function(
data,
align = "left",
split = FALSE,
keep_with_next = TRUE
) {

# Perform input object validation
stop_if_not_gt(data = data)

# Composition of caption OOXML -----------------------------------------------

# Create the table caption
caption_xml <-
create_table_caption_component_xml(
data = data,
align = align,
keep_with_next = keep_with_next
)

caption_xml
}

#' Generate ooxml for the table body
#'
#' @param data A processed table object that is created using the `build_data()`
#' function.
#' @param align left, center (default) or right.
#' @param split TRUE or FALSE (default) indicating whether activate Word option
#' 'Allow row to break across pages'.
#' @param keep_with_next TRUE (default) or FALSE indicating whether a table
#' should use Word option 'keep rows together' is activated when TRUE
#' @param embedded_heading TRUE or FALSE (default) indicating whether a table
#' should add the title and subtitle at the top of the table.
#'
#' @noRd
as_word_tbl_body <- function(
data,
align = "center",
split = FALSE,
keep_with_next = TRUE,
embedded_heading = FALSE
) {

# Perform input object validation
stop_if_not_gt(data = data)

# Composition of table Word OOXML -----------------------------------------------

# Create the table properties component
table_props_component <- create_table_props_component_xml(data = data, align = align)

# # Create the heading component
if (embedded_heading) {
heading_component <- create_heading_component_xml(data = data, split = split, keep_with_next = keep_with_next)
} else {
heading_component <- NULL
}

# Create the columns component
columns_component <- create_columns_component_xml(data = data, split = split, keep_with_next = keep_with_next)

# Create the body component
body_component <- create_body_component_xml(data = data, split = split, keep_with_next = keep_with_next)

# Create the footnotes component
footnotes_component <- create_footnotes_component_xml(data = data, split = split, keep_with_next = keep_with_next)

# Create the source notes component
source_notes_component <- create_source_notes_component_xml(data = data, split = split, keep_with_next = keep_with_next)

# Compose the Word OOXML table
word_tbl <-
xml_tbl(
paste0(
table_props_component,
heading_component,
columns_component,
body_component,
footnotes_component,
source_notes_component,
collapse = ""
)
)

as.character(word_tbl)
}

#' Extract a summary list from a **gt** object
#'
Expand Down Expand Up @@ -610,7 +784,7 @@ as_rtf <- function(data) {
#'
#' @family Export Functions
#' @section Function ID:
#' 13-5
#' 13-6
#'
#' @export
extract_summary <- function(data) {
Expand Down
3 changes: 3 additions & 0 deletions R/format_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -2792,6 +2792,9 @@ fmt_markdown <- function(
rtf = function(x) {
markdown_to_rtf(x)
},
word = function(x) {
markdown_to_xml(x)
},
default = function(x) {
vapply(
x,
Expand Down
16 changes: 16 additions & 0 deletions R/print.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ knitr_is_rtf_output <- function() {
"rtf" %in% knitr::opts_knit$get("rmarkdown.pandoc.to")
}

knitr_is_word_output <- function() {

"word_document" %in% rmarkdown::all_output_formats(knitr::current_input())
}

#' Knit print the table
#'
#' This facilitates printing of the HTML table within a knitr code chunk.
Expand All @@ -34,10 +39,21 @@ knitr_is_rtf_output <- function() {
knit_print.gt_tbl <- function(x, ...) {

if (knitr_is_rtf_output()) {

x <- as_rtf(x)

} else if (knitr::is_latex_output()) {

x <- as_latex(x)

} else if (knitr_is_word_output()) {

x <-
paste("```{=openxml}", as_word(x), "```\n\n", sep = "\n") %>%
knitr::asis_output()

} else {

# Default to HTML output
x <- as.tags.gt_tbl(x, ...)
}
Expand Down
Loading

0 comments on commit a585bd6

Please sign in to comment.