You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny:如何将含多行单元格的DataTable导出为PDF及Excel?

保留格式导出带多行单元格的Shiny表格(PDF/Excel)

问题说明

Shiny中的表格使用HTML标签(<br>换行、<b>加粗)在界面显示正常,但DT默认PDF导出、huxtable导出均无法保留这些格式;同时需要实现Excel导出时也保留单元格内换行与格式,且方案需适配shinyapps.io(不能依赖外部应用)。


PDF导出实现(保留换行与加粗)

核心思路是将HTML格式转换为Markdown格式,再通过rmarkdown渲染成PDF,无需外部工具,完全适配shinyapps.io。

完整代码

library(shiny)
library(DT)
library(rmarkdown)
library(stringr)

# 预处理数据:将HTML标签转成Markdown格式
data <- data.frame(
  Name = c("Mr A", "Mrs B"),
  Description = c(
    "This is line 1.<br>Line 2.",
    "This is another cell with line 1.<br>Line 2 has some <b>bold text</b>."
  )
)
# 替换HTML换行和加粗标签
data$Description <- str_replace_all(data$Description, "<br>", "\n")
data$Description <- str_replace_all(data$Description, "<b>(.*?)</b>", "**\\1**")

ui <- dashboardPage(
  skin = "black",
  dashboardHeader(disable = TRUE),
  dashboardSidebar(disable = TRUE),
  dashboardBody(
    DT::dataTableOutput("Table"),
    br(),
    downloadButton("export_pdf", "导出PDF(保留格式)")
  )
)

server <- function(input, output, session) {
  # 显示表格
  output$Table <- DT::renderDataTable(
    data,
    extensions = 'Buttons',
    rownames = FALSE,
    options = list(
      paging = FALSE,
      searching = TRUE,
      fixedColumns = TRUE,
      autoWidth = TRUE,
      ordering = TRUE,
      dom = '<t>'
    ),
    escape = FALSE,
    class = "display"
  )
  
  # PDF导出逻辑
  output$export_pdf <- downloadHandler(
    filename = function() { "formatted_table.pdf" },
    content = function(file) {
      # 临时Rmd文件内容
      rmd_content <- "
---
output: pdf_document
---

```{r echo=FALSE, results='asis'}
knitr::kable(data, format = 'markdown')
"
  # 写入临时Rmd
  temp_rmd <- tempfile(fileext = ".Rmd")
  writeLines(rmd_content, temp_rmd)
  # 渲染成PDF
  render(temp_rmd, output_file = file)
}

)
}

shinyApp(ui, server)

### 关键步骤
1. **格式转换**:把HTML的`<br>`替换为换行符`\n`,`<b>...</b>`替换为Markdown粗体语法`**...**`,确保Markdown能识别格式。
2. **Rmarkdown渲染**:通过临时Rmd文件调用`knitr::kable`生成带格式的表格,再渲染为PDF,全程无需外部依赖。

---

## Excel导出实现(保留换行与加粗)
Excel原生支持单元格内换行和字体加粗,使用`openxlsx`包可以直接控制单元格格式,完美适配需求。

### 完整代码
```r
library(shiny)
library(DT)
library(openxlsx)
library(stringr)

data <- data.frame(
  Name = c("Mr A", "Mrs B"),
  Description = c(
    "This is line 1.<br>Line 2.",
    "This is another cell with line 1.<br>Line 2 has some <b>bold text</b>."
  )
)

ui <- dashboardPage(
  skin = "black",
  dashboardHeader(disable = TRUE),
  dashboardSidebar(disable = TRUE),
  dashboardBody(
    DT::dataTableOutput("Table"),
    br(),
    downloadButton("export_excel", "导出Excel(保留格式)")
  )
)

server <- function(input, output, session) {
  output$Table <- DT::renderDataTable(
    data,
    extensions = 'Buttons',
    rownames = FALSE,
    options = list(
      paging = FALSE,
      searching = TRUE,
      fixedColumns = TRUE,
      autoWidth = TRUE,
      ordering = TRUE,
      dom = '<t>'
    ),
    escape = FALSE,
    class = "display"
  )
  
  # Excel导出逻辑
  output$export_excel <- downloadHandler(
    filename = function() { "formatted_table.xlsx" },
    content = function(file) {
      # 创建工作簿和工作表
      wb <- createWorkbook()
      addWorksheet(wb, "Table")
      
      # 预处理数据:替换HTML换行
      export_data <- data
      export_data$Description <- str_replace_all(export_data$Description, "<br>", "\n")
      
      # 写入基础数据
      writeData(wb, "Table", export_data, startRow = 1, startCol = 1, rowNames = FALSE)
      
      # 设置单元格自动换行
      wrap_style <- createStyle(wrapText = TRUE)
      addStyle(wb, "Table", wrap_style, rows = 2:(nrow(export_data)+1), cols = 2, gridExpand = TRUE)
      
      # 处理加粗格式:提取<b>标签内的文本并设置加粗
      for (i in 1:nrow(export_data)) {
        desc <- export_data$Description[i]
        if (str_detect(desc, "<b>(.*?)</b>")) {
          bold_text <- str_extract(desc, "<b>(.*?)</b>") %>% str_remove_all("<b>|</b>")
          # 找到加粗文本在单元格中的位置
          start_pos <- str_locate(desc, "<b>")[1,1]
          end_pos <- str_locate(desc, "</b>")[1,2] - 7 # 减去标签长度
          # 创建加粗样式
          bold_style <- createStyle(textDecoration = "bold")
          addStyle(wb, "Table", bold_style, rows = i+1, cols = 2, 
                   startChar = start_pos, endChar = end_pos,
                   gridExpand = FALSE, stack = TRUE)
          # 移除HTML标签
          export_data$Description[i] <- str_remove_all(desc, "<b>|</b>")
          # 更新单元格内容
          writeData(wb, "Table", export_data$Description[i], startRow = i+1, startCol = 2, colNames = FALSE)
        }
      }
      
      # 保存工作簿
      saveWorkbook(wb, file, overwrite = TRUE)
    }
  )
}

shinyApp(ui, server)

关键步骤

  1. 换行设置:将HTML的<br>替换为Excel识别的换行符\n,并设置单元格wrapText = TRUE实现自动换行。
  2. 加粗格式:提取<b>标签内的文本,通过addStyle指定字符位置设置加粗样式,最后移除HTML标签更新单元格内容。

整合PDF+Excel导出的完整代码

可以将两个导出功能合并到同一个Shiny应用中:

library(shiny)
library(DT)
library(rmarkdown)
library(openxlsx)
library(stringr)

data <- data.frame(
  Name = c("Mr A", "Mrs B"),
  Description = c(
    "This is line 1.<br>Line 2.",
    "This is another cell with line 1.<br>Line 2 has some <b>bold text</b>."
  )
)
# 预处理用于PDF的Markdown格式数据
pdf_data <- data
pdf_data$Description <- str_replace_all(pdf_data$Description, "<br>", "\n")
pdf_data$Description <- str_replace_all(pdf_data$Description, "<b>(.*?)</b>", "**\\1**")

ui <- dashboardPage(
  skin = "black",
  dashboardHeader(disable = TRUE),
  dashboardSidebar(disable = TRUE),
  dashboardBody(
    DT::dataTableOutput("Table"),
    br(),
    downloadButton("export_pdf", "导出PDF(保留格式)"),
    br(), br(),
    downloadButton("export_excel", "导出Excel(保留格式)")
  )
)

server <- function(input, output, session) {
  output$Table <- DT::renderDataTable(
    data,
    extensions = 'Buttons',
    rownames = FALSE,
    options = list(
      paging = FALSE,
      searching = TRUE,
      fixedColumns = TRUE,
      autoWidth = TRUE,
      ordering = TRUE,
      dom = '<t>'
    ),
    escape = FALSE,
    class = "display"
  )
  
  # PDF导出
  output$export_pdf <- downloadHandler(
    filename = function() { "formatted_table.pdf" },
    content = function(file) {
      rmd_content <- "
---
output: pdf_document
---

```{r echo=FALSE, results='asis'}
knitr::kable(pdf_data, format = 'markdown')
"
  temp_rmd <- tempfile(fileext = ".Rmd")
  writeLines(rmd_content, temp_rmd)
  render(temp_rmd, output_file = file)
}

)

Excel导出

output$export_excel <- downloadHandler(
filename = function() { "formatted_table.xlsx" },
content = function(file) {
wb <- createWorkbook()
addWorksheet(wb, "Table")

export_data <- data
  export_data$Description <- str_replace_all(export_data$Description, "<br>", "\n")
  
  writeData(wb, "Table", export_data, startRow = 1, startCol = 1, rowNames = FALSE)
  
  wrap_style <- createStyle(wrapText = TRUE)
  addStyle(wb, "Table", wrap_style, rows = 2:(nrow(export_data)+1), cols = 2, gridExpand = TRUE)
  
  for (i in 1:nrow(export_data)) {
    desc <- export_data$Description[i]
    if (str_detect(desc, "<b>(.*?)</b>")) {
      bold_text <- str_extract(desc, "<b>(.*?)</b>") %>% str_remove_all("<b>|</b>")
      start_pos <- str_locate(desc, "<b>")[1,1]
      end_pos <- str_locate(desc, "</b>")[1,2] - 7
      bold_style <- createStyle(textDecoration = "bold")
      addStyle(wb, "Table", bold_style, rows = i+1, cols = 2, 
               startChar = start_pos, endChar = end_pos,
               gridExpand = FALSE, stack = TRUE)
      export_data$Description[i] <- str_remove_all(desc, "<b>|</b>")
      writeData(wb, "Table", export_data$Description[i], startRow = i+1, startCol = 2, colNames = FALSE)
    }
  }
  
  saveWorkbook(wb, file, overwrite = TRUE)
}

)
}

shinyApp(ui, server)

内容的提问来源于stack exchange,提问作者PLA
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:25:08