Import data from XML files into data.frame
With a few XML files to read you could have done something like this to address your concerns, where the files are only read at once, but all loaded into memory at the same time:

subdirs &lt;- strsplit(dirname(filenames),
                    split = .Platform$file.sep)
subdirs &lt;- lapply(subdirs, rev)
job   &lt;- sapply(subdirs, `[[`, 3)
build &lt;- sapply(subdirs, `[[`, 1)
xmls &lt;- lapply(filenames, xmlParse)
duration &lt;- sapply(xmls, xpathSApply, "//duration", xmlValue)
result   &lt;- sapply(xmls, xpathSApply, "//result", xmlValue)
build.data &lt;- data.frame(job, build, result, duration)


With thousands of files though, it makes more sense to process the files one by one and only keep the useful information before moving from one file to the next. It also makes sense to write a function to process each file. It could be:

build.info &lt;- function(file, xml_fields = c("duration", "result")) {
   res &lt;- list()
   # process filepath
   subdirs &lt;- rev(unlist(strsplit(dirname(file),
                                  split = .Platform$file.sep)))
   res$job   &lt;- subdirs[[3]]
   res$build &lt;- subdirs[[1]]
   # process xml data
   doc &lt;- xmlTreeParse(file)
   build &lt;- doc$doc$children$build
   res[xml_fields] &lt;- lapply(build[xml_fields], xmlValue)
   # return as a data.frame
   as.data.frame(res)
}


See how the function returns a one row data.frame. Then you can call the function on all files via lapply and bind all the outputs together:

build.data &lt;- do.call(rbind, lapply(filenames, build.info))


With a few changes, you can write a more general function that will take one or more files and do the binding itself (like file.info does)

build.info &lt;- function(file, xml_fields = c("duration", "result")) {
   stopifnot(length(file) &gt; 0L)
   if (length(file) == 1L) {
      res &lt;- list()
      # process filepath
      subdirs &lt;- rev(unlist(strsplit(dirname(file),
                                     split = .Platform$file.sep)))
      res$job   &lt;- subdirs[[1]]
      res$build &lt;- subdirs[[3]]
      # process xml data
      doc &lt;- xmlTreeParse(file)
      build &lt;- doc$doc$children$build
      res[xml_fields] &lt;- lapply(build[xml_fields], xmlValue)
      # return data.frame
      as.data.frame(res)
   } else {
      do.call(rbind, lapply(file, build.info))
   }
}

build.data &lt;- build.info(filenames)