Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions R/writeODS.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,18 @@

}

.cell_out <- function(type, value, con) {
escaped_value <- .escape_xml(value)
cat("<table:table-cell office:value-type=\"", type,
"\" office:value=\"", escaped_value,
"\" table:style-name=\"ce1\"><text:p>", escaped_value,
"</text:p></table:table-cell>",
sep = "",
file = con)
.cell_out <- function(type, value, con, write_empty_cell = FALSE) {
if (isTRUE(write_empty_cell)) {
cat("<table:table-cell/>", file = con)
} else {
escaped_value <- .escape_xml(value)
cat("<table:table-cell office:value-type=\"", type,
"\" office:value=\"", escaped_value,
"\" table:style-name=\"ce1\"><text:p>", escaped_value,
"</text:p></table:table-cell>",
sep = "",
file = con)
}
}

## CREATION OF sysdata
Expand Down Expand Up @@ -78,12 +82,16 @@
}
for (j in colj) {
value <- as.character(x[i, j, drop = TRUE])
write_empty_cell <- FALSE
if (is.na(value) && !na_as_string) {
write_empty_cell <- TRUE
}
if (is.na(value) && na_as_string) {
type <- "string"
} else {
type <- types[j]
}
.cell_out(type = type, value = value, con = con)
.cell_out(type = type, value = value, con = con, write_empty_cell = write_empty_cell)
}
cat("</table:table-row>", file = con)
}
Expand Down Expand Up @@ -122,7 +130,7 @@
#' @param update logical, TRUE indicates that the sheet with sheet_name in the existing file (path) should be updated with the content of x. If a sheet with sheet_name does not exist, an exception is thrown. Please also note that writing is slower if TRUE. Default is FALSE.
#' @param row_names logical, TRUE indicates that row names of x are to be included in the sheet. Default is FALSE.
#' @param col_names logical, TRUE indicates that column names of x are to be included in the sheet. Default is TRUE.
#' @param na_as_string logical, TRUE indicates that NAs are written as string.
#' @param na_as_string logical, TRUE indicates that NAs are written as string; FALSE indicates that NAs are written as empty cells
#' @return An ODS file written to the file path location specified by the user. The value of \code{path} is also returned invisibly.
#' @author Detlef Steuer <steuer@@hsu-hh.de>, Thomas J. Leeper <thosjleeper@@gmail.com>, John Foster <john.x.foster@@nab.com.au>, Chung-hong Chan <chainsawtiney@@gmail.com>
#' @examples
Expand All @@ -133,7 +141,7 @@
#' write_ods(PlantGrowth, "mtcars.ods", append = TRUE, sheet = "plant")
#' }
#' @export
write_ods <- function(x, path, sheet = "Sheet1", append = FALSE, update = FALSE, row_names = FALSE, col_names = TRUE, na_as_string = TRUE) {
write_ods <- function(x, path = tempfile(fileext = ".ods"), sheet = "Sheet1", append = FALSE, update = FALSE, row_names = FALSE, col_names = TRUE, na_as_string = FALSE) {
## setup temp directory
## one can't just use tempdir() because it is the same in the same session
temp_ods_dir <- file.path(tempdir(), stringi::stri_rand_strings(1, 20, pattern = "[A-Za-z0-9]"))
Expand Down
6 changes: 3 additions & 3 deletions man/write_ods.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions tests/testthat/test_write_ods.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,20 @@ test_that("na_as_string, #79", {
contentfile <- file.path(temp_odsdir, "content.xml")
expect_false(grepl("office:value-type=\"string\" office:value=\"NA\"", suppressWarnings(readLines(contentfile))))
})

test_that("na_as_string, round trip", {
iris_na <- tibble::as_tibble(iris)
iris_na[1,1] <- NA
iris_na[2,1] <- NA
iris_na[5,2] <- NA
iris_na$Species <- as.character(iris_na$Species)
expect_true(all.equal(iris_na, readODS::read_ods(readODS::write_ods(iris_na, na_as_string = FALSE))))
## default
expect_true(all.equal(iris_na, readODS::read_ods(readODS::write_ods(iris_na))))
expect_false(is.logical(all.equal(iris_na, readODS::read_ods(readODS::write_ods(iris_na, na_as_string = TRUE)))))
## sanity check
iris2 <- tibble::as_tibble(iris)
iris2$Species <- as.character(iris2$Species)
expect_true(all.equal(iris2, readODS::read_ods(readODS::write_ods(iris2, na_as_string = FALSE))))
expect_true(all.equal(iris2, readODS::read_ods(readODS::write_ods(iris2, na_as_string = TRUE))))
})
28 changes: 28 additions & 0 deletions vignettes/overview.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ list_ods_sheets("plant.ods")

## readODS 2.0.0

Starting from 2.0.0, `write_ods` writes `NA` as empty by default.

```{r, empty1}
PlantGrowth2 <- tibble::as_tibble(PlantGrowth)
PlantGrowth2[1,1] <- NA
PlantGrowth2$group <- as.character(PlantGrowth2$group)

## NA is preseved; weight is still <dbl>
read_ods(write_ods(PlantGrowth2))
```

If you want `NA` to be written literally as the string "NA", use `na_as_string`. You should literally see the string "NA" when the file is opened with LibreOffice, for example.

But the string "NA" messes up the automatic type inference of `read_ods`.

```{r, empty2}
## NA is preseved; but weight is now <chr>
read_ods(write_ods(PlantGrowth2, na_as_string = TRUE))
```

Of course you can fix this by specifying `col_types`.

```{r, empty3}
## NA is preseved; but weight is now <chr>
read_ods(write_ods(PlantGrowth2, na_as_string = TRUE),
col_types = readr::cols(weight = readr::col_double()))
```

Several functions were removed in readODS 2.0.0. Please consider the API of `readODS` mature and there should not be any breaking change until readODS 3.0.0.

### `ods_sheets`
Expand Down