首页 > 解决方案 > 将 XML 文本读入 tibble

问题描述

我想像这样获取一个 xml 文件(我称之为“2019-05-24.xml”):

<file>
    <header>
        <filename>2019-05-24</filename>
    </header>
    <body>
        <div type="article">
            <head>First test article</head>
            <p>Some information.</p>
            <p>Some other information.</p>
        </div>
        <div type="section" feature="essay">
            <head>Test essay</head>
            <p>An argument.</p>
            <p>Supporting evidence.</p>
        </div>
    </body>
</file>

把它变成这样的小标题

# A tibble: 3 x 6
  filename        seq type    feature head       text                                                                    
  <chr>         <int> <chr>   <chr>   <chr>      <chr>                                                                  
1 2019-05-24.xml    1 article NA      First test "Some information. Other information. Yet…
2 2019-05-24.xml    2 section essay   Test essay "An argument. Supporting evidence."                              
3 2019-05-24.xml    3 index   NA      NA         "Article.....1 Essay....2"      

这让我走到了一半:

sample <- "2019-05-24.xml"

extract_data <- function(x){
  divs <- x %>% 
    read_xml() %>%
    xml_child(2) %>%
    xml_find_all(".//div")
  text <- xml_text(divs)
  type <- xml_attr(divs, "type")
  feature <- xml_attr(divs, "feature")
  seq <- seq_along(divs)
  test_tibble <- tibble(filename = x, seq = seq, type = type, feature = feature, text = text)
}

lapply(sample, extract_data)

不幸的是,结果连接了headp文本:

# A tibble: 3 x 5
  filename       seq type    feature text                                                       
  <chr>        <int> <chr>   <chr>   <chr>                                                      
1 2019-05-24.…     1 article NA      "First test articleSome information.\n            Other in…
2 2019-05-24.…     2 section essay   Test essayAn argument.Supporting evidence.                 
3 2019-05-24.…     3 index   NA      Article.....1Essay....2                                    

问题一:头部

如果我head以与提取文本相同的方式提取

head <- sample %>% 
  read_xml() %>%
  xml_child(2) %>%
  xml_find_all(".//div/head//text()")

我收到一个错误,因为第三个div不包含head

Error: Tibble columns must have consistent lengths, only values of length one are recycled:
* Length 2: Column `head`
* Length 3: Columns `seq`, `type`, `feature`

如果aNA中没有,我可以让这个函数返回吗?headdiv

问题 2:在 div 中读取文本

我只想阅读divs列表中三个项目或节点中的每一个中的文本。我可以使类似text <- divs %>% xml_children %>% xml_text()(返回整个文件中的每个孩子)在每个节点上单独工作吗?我尝试了各种apply()变体。xml_find_all我认为我在 XPath 和and上做错了xml_text,但我想不通。

标签: rxmltidyverse

解决方案


为了解决您的问题,需要单独解析每个 div,然后创建一个数据框列表,然后将所有内容 cbind 在一起。

library(xml2)
library(tibble)

sample <- "2019-05-24.xml"

extract_data <- function(x){
  #read file
  file<-read_xml(x)
  #extract divs, get type attribute and 
  divs <- file %>% xml_find_all(".//div")
  type <- xml_attr(divs, "type")

  #find the head and p for each div
  #returns a list of data frames
  output<-lapply(divs, function(d){
    header<- d %>% xml_find_first(".//head") %>% xml_text()
    text<-d %>% xml_find_all(".//p") %>% xml_text() %>%  paste( collapse = ", ")
    data.frame(head=header, text)
  })
  #bind everything up into a tibble.
  answer<-do.call(rbind, output)
  test_tibble <- cbind(tibble(filename = x, seq = 1:nrow(answer), type = type), answer)
}

lapply(sample, extract_data)



#[[1]]
        filename seq    type               head                                       text
#1 2019-05-24.xml   1 article First test article Some information., Some other information.
#2 2019-05-24.xml   2 section         Test essay         An argument., Supporting evidence.

推荐阅读