0

The following code extracts one attribute (or all) from an XML file:

library(xml2);library(magrittr);library(readr);library(tibble);library(knitr)   
fname<-'https://raw.githubusercontent.com/wardblonde/ODM-to-i2b2/master/odm/examples/CDISC_ODM_example_3.xml'
fname
x<-read_xml(fname)
xpath="//d1:ItemDef"
itemsNames <- x %>% xml_find_all(xpath, ns=xml_ns(x)) %>%  xml_attr('Name')
items <- x %>% xml_find_all(xpath, ns=xml_ns(x))

Item looks like this:

<ItemDef OID="IT.ABNORM" Name="Normal/Abnormal/Not Done" DataType="integer" Length="1" ...

Sample file can be viewed here: https://raw.githubusercontent.com/wardblonde/ODM-to-i2b2/master/odm/examples/CDISC_ODM_example_3.xml

Using pipes and xml_attr, what is the best way to extract both the Name and DataType attributes and have them rbinded?

Ideally it would be a single line of super efficient piped code. I can extract names and types and have 'data.frame(name=names,type=types)' but that seems not the best and most modern.

The result should be a tibble with columns name and data type.

4

1 回答 1

2
library(purrr)

map(items, xml_attrs) %>% 
  map_df(as.list) %>% 
  select(Name, DataType)
## # A tibble: 94 × 2
##                                   Name DataType
##                                  <chr>    <chr>
## 1             Normal/Abnormal/Not Done  integer
## 2          Actions taken re study drug     text
## 3                 Actions taken, other     text
## 4    Stop Day - Enter Two Digits 01-31     text
## 5                    Derived Stop Date     text
## 6  Stop Month - Enter Two Digits 01-12     text
## 7    Stop Year - Enter Four Digit Year     text
## 8                              Outcome     text
## 9           Relationship to study drug     text
## 10                            Severity     text
## # ... with 84 more rows

一个“基础”版本:

lapply(items, xml_attrs) %>% 
  lapply(function(x) as.data.frame(as.list(x))[,c("Name", "DataType")]) %>% 
  do.call(rbind, .) %>%
  tbl_df()

注意:^^ 的一个问题是,如果NameDataType缺失,那么你就是 SOL。您可以通过以下方式缓解这种情况:

lapply(items, xml_attrs) %>% 
  lapply(function(x) as.data.frame(as.list(x))[,c("Name", "DataType")]) %>% 
  data.table::rbindlist(fill=TRUE) %>% 
  tbl_df()

或者:

lapply(items, xml_attrs) %>% 
  lapply(function(x) as.data.frame(as.list(x))[,c("Name", "DataType")]) %>% 
  bind_rows() %>% 
  tbl_df()

如果你不喜欢purrr

于 2016-12-22T16:57:44.177 回答