Извлечение данных из XML в R

Мне нужно извлечь определенные данные из XML, которые выглядят следующим образом (упрощено для краткости)

<Doc name="Doc1">
    <Lists Count="1">
        <List Name="List1">
            <Points Count="3">
                <Point Id="1">
                    <Tags Count ="1">"a"</Tags>
                    <Point Position="1"  /> 
                </Point>
                <Point Id="2">
                    <Point Position="2"  /> 
                </Point>
                <Point Id="3">
                    <Tags Count="1">"c"</Tags>
                    <Point Position="3"  /> 
                </Point>
            </Points>
        </List>
    </Lists>
</Doc>

На выходе должен быть фрейм данных, соответствующий тегу и положению для каждого идентификатора точки.

    Point  Tag Position
1     1    a        1
2     2 <NA>        2
3     3    c        3

Я новичок в XML, я играл с пакетом xml2. До сих пор я мог извлекать каждую переменную отдельно, но поскольку некоторые точки могут не иметь данных тега, я не могу найти способ сопоставления между тремя параметрами.

> library(xml2)
> xml_data<-read_xml(...)
> xml_data %>% xml_find_all("//Point") %>% xml_attr("Id")
[1] "1" "2" "3"
> xml_data %>% xml_find_all("//Vertical") %>% xml_attr("Position")
[1] "1" "2" "3"
> xml_data %>% xml_find_all("//Tags") %>% xml_text()
[1] "\"a\"" "\"c\""

r xml
person Sasha    schedule 16.10.2016    source источник


Ответы (2)


purrr и xml2 хорошо сочетаются:

library(xml2)
library(purrr)

txt <- '<Doc name="Doc1">
    <Lists Count="1">
        <List Name="List1">
            <Points Count="3">
                <Point Id="1">
                    <Tags Count ="1">"a"</Tags>
                    <Point Position="1"  /> 
                </Point>
                <Point Id="2">
                    <Point Position="2"  /> 
                </Point>
                <Point Id="3">
                    <Tags Count="1">"c"</Tags>
                    <Point Position="3"  /> 
                </Point>
            </Points>
        </List>
    </Lists>
</Doc>'

doc <- read_xml(txt)
xml_find_all(doc, ".//Points/Point") %>% 
  map_df(function(x) {
    list(
      Point=xml_attr(x, "Id"),
      Tag=xml_find_first(x, ".//Tags") %>%  xml_text() %>%  gsub('^"|"$', "", .),
      Position=xml_find_first(x, ".//Point") %>% xml_attr("Position")
    )
  })
## # A tibble: 3 × 3
##   Point   Tag Position
##   <chr> <chr>    <chr>
## 1     1     a        1
## 2     2  <NA>        2
## 3     3     c        3
person hrbrmstr    schedule 16.10.2016

Запустите xpathApply над //Points/Point узлами и для каждого такого узла x получите Id, Tag (или NA, если нет) и Position:

library(XML)

doc <- xmlTreeParse(Lines, asText = TRUE, useInternalNodes = TRUE)

do.call("rbind", xpathApply(doc, "//Points/Point", function(x) 
  data.frame(Id = as.numeric(xmlAttrs(x)[["Id"]]), 
             Tags = c(gsub('"', '', xmlValue(x[["Tags"]])), NA)[[1]],
             Position = as.numeric(xmlAttrs(x[["Point"]])[["Position"]],
             stringsAsFactors = FALSE))))

давая:

  Id Tags Position
1  1    a        1
2  2 <NA>        2
3  3    c        3

вариант

Вариант вышеизложенного, дающий тот же ответ, заключается в следующем. На каждом узле Point он создает строку атрибутов и значений, а затем использует read.table для ее чтения:

library(XML)

doc <- xmlTreeParse(Lines, asText = TRUE, useInternalNodes = TRUE)

xp <- xpathSApply(doc, "//Points/Point", function(x) paste(
        xmlAttrs(x)[["Id"]],  
        c(gsub('"', '', xmlValue(x[["Tags"]])), NA)[[1]], 
        xmlAttrs(x[["Point"]])[["Position"]]))
read.table(text = xp, col.names = c("Id", "Tags", "Position"), as.is = TRUE)

Примечание. Введите Lines:

Lines <- '<Doc name="Doc1">
    <Lists Count="1">
        <List Name="List1">
            <Points Count="3">
                <Point Id="1">
                    <Tags Count ="1">"a"</Tags>
                    <Point Position="1"  /> 
                </Point>
                <Point Id="2">
                    <Point Position="2"  /> 
                </Point>
                <Point Id="3">
                    <Tags Count="1">"c"</Tags>
                    <Point Position="3"  /> 
                </Point>
            </Points>
        </List>
    </Lists>
</Doc>'
person G. Grothendieck    schedule 16.10.2016