How to convert dataframe to xml using xml2 package?

2k views Asked by At

I'm trying to update an xml file with new nodes using xml2. It's easy if I just write everything manually as text,

oldXML <- read_xml("<Root><Trial><Number>3.14159 </Number><Adjective>Fast </Adjective></Trial></Root>")

but I'm developing an application that will run calculations and then put those values into the xml, so I need a mix of character and variables. It ends up looking like:

var1 <- 4.567
var2 <- "Slow"
newLine <- read_xml(paste0("<Trial><Number>",var1," </Number><Adjective>",var2," </Adjective></Trial>"))
xml_add_child(oldXML,newLine)

I suspect there's a much less kludgy way to do this than using paste0, but I can't get anything else to work. I'd like to be able to just instruct it to update the xml by reference to the dataframe, such that it can create new trials:

<Trial>
  <Number>df$number[1]</Number>
  <Adjective>df$adjective[1]</Adjective>
</Trial>
<Trial>
  <Number>df$number[2]</Number>
  <Adjective>df$adjective[2]</Adjective>
</Trial>

Is there any way to create new Trial nodes in approximately that fashion, or at least more naturally than using paste0 to insert variables? Is this something the XML package does better than xml2?

2

There are 2 answers

1
Ista On BEST ANSWER

If you have your new values in a data.frame like this:

vars <- data.frame(Number = c(4.567, 3.211),
                   Adjective = c("Slow", "Slow"),
                   stringsAsFactors = FALSE)

you can convert it to a list of xml_document's as follows:

vars_xml <- lapply(purrr::transpose(vars),
                   function(x) {
                       as_xml_document(list(Trial = lapply(x, as.list)))
                   })

Then you can add the new nodes to the original xml:

for(trial in vars_xml) xml_add_child(oldXML, trial)

I don't know that this is better than your paste approach. Either way, you can wrap it in a function so you only have to write the ugly code once.

0
D. Woods On

Here's a solution that builds on @Ista's excellent answer. Basically, I've dropped the first lapply in favor of purrr::map (we could probably replace the second lapply with a map, but I couldn't find a more readable way to accomplish that).

library(purrr)

vars_xml <- transpose(vars) %>% 
   map(~as_xml_document(list(Trial = lapply(.x, as.list))))