【问题标题】:Read XML texts into tibble将 XML 文本读入 tibble
【发布时间】:2019-05-24 23:11:48
【问题描述】:

我想像这样获取一个 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                                    

问题1:头部

如果我以与提取文本相同的方式提取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`

如果div 中没有head,我能否让这个函数返回NA

问题 2:在 div 中读取文本

我只想阅读divs 列表中三个项目或节点中的每一个中的文本。我可以让text &lt;- divs %&gt;% xml_children %&gt;% xml_text()(它返回整个文件中的每个孩子)在每个节点上单独工作吗?我尝试了各种apply() 变体。我想我在 XPath 和 xml_find_allxml_text 上做错了,但我想不通。

【问题讨论】:

    标签: r xml tidyverse


    【解决方案1】:

    为了解决您的问题,需要单独解析每个 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.
    

    【讨论】:

    • 这可以满足我的需要——谢谢!——但我仍然不太明白为什么我们需要函数的最后两行来实现它们。为什么output/answer与tibble的其他列不同,需要使用cbind添加?我猜这是因为列表不能直接添加到 tibble,所以它的行必须先绑定在一起?很抱歉问了一个简单的问题。
    • 或者说,divs生成的列表和output生成的列表有什么不同?
    • @WillHanley,好问题。变量“输出”是一个数据框列表(在这种情况下,只有一行),因此函数do.call 将数据框列表连接成一个具有多行和多列的数据框(“答案”) “头”和“文本”。函数的最后一行 cbind 将 'filename'、'sequence' 和 'type' 列添加到 'head'、'text' 列中。我希望这有帮助。为了更好地可视化这一点,请尝试向函数添加一些打印语句
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2023-03-08
    • 2020-06-26
    • 1970-01-01
    • 2016-10-24
    • 1970-01-01
    相关资源
    最近更新 更多