【问题标题】:Extract text from XML, but file has duplicated node-names从 XML 中提取文本,但文件具有重复的节点名称
【发布时间】:2018-01-27 14:14:15
【问题描述】:

我正在尝试将一些数据从 XML 文件导入 R data.frame。 虽然我对 R 非常有经验,但我以前从未使用过 XML,所以这一切对我来说都是新事物,我感到有些失落。

下面提供了一个 XML 示例:

<ArchivedIncident ID="100">
    <attributes>
        <entry>
            <key>TEST1</key>
            <value>
                <type>S</type>
                <value/>
            </value>
        </entry>
        <entry>
            <key>TEST2</key>
            <value>
                <type>S</type>
                <value>12</value>
            </value>
        </entry>
        <entry>
            <key>TEST3</key>
            <value>
                <type>T</type>
                <value>A</value>
            </value>
        </entry>
        <entry>
            <key>TEST4</key>
            <value>
                <type>S</type>
                <value/>
            </value>
        </entry>
    </attributes>
</ArchivedIncident>
<ArchivedIncident ID="101">
    <attributes>
        <entry>
            <key>TEST1</key>
            <value>
                <type>S</type>
                <value>BLAH</value>
            </value>
        </entry>
        <entry>
            <key>TEST2</key>
            <value>
                <type>S</type>
                <value/>
            </value>
        </entry>
        <entry>
            <key>TEST3</key>
            <value>
                <type>T</type>
                <value/>
            </value>
        </entry>
        <entry>
            <key>TEST4</key>
            <value>
                <type>S</type>
                <value/>
            </value>
        </entry>
    </attributes>
</ArchivedIncident>

我想要完成的是一个如下所示的 R-data.frame:

ID     TEST1    TEST2    TEST3    TEST4
100    NA       12       A        NA
101    BLAH     NA       NA       NA

到目前为止我想出了什么:

使用 xml2 包,我可以读取 ID 的使用:

require(xml2)
doc <- read_xml("./data/file.xml")
df <- data.frame( 
  ID = xml_attr( xml_find_all( doc, ".//ArchivedIncident" ), "ID" )
  )

到目前为止一切顺利,但现在我不知道如何提取其余部分。有多个节点,都命名为“entry”、“value”和“type”。如何从(用作列名)中提取文本,以及该键的值(在该键之后。

复杂的因素是,并非每个人都有价值。我想为空值插入一个“NA”。 在另一种情况下,我可以为此使用自定义函数,但我不确定(因为我不知道如何提取正确的文本)这是否可以在这里工作。

L <- xml_find_all(doc, ".//ArchivedIncident")
FindAllValues <- function(node){
    tmp <- lapply(L, xml_find_all, paste0(".//", node))
    tmp <- lapply(tmp, xml_text)
    tmp[!sapply(tmp, function(y) length(y == 0))] <- NA
    return(tmp)
}

【问题讨论】:

    标签: r xml


    【解决方案1】:
    library(xml2)
    library(tidyverse)
    
    doc <- read_xml("file.xml")
    
    xml_find_all(doc, ".//ArchivedIncident") %>% # iterate over each incident
      map_df(~{
        set_names(
          xml_find_all(.x, ".//value/value") %>% xml_text(), # get entry values
          xml_find_all(.x, ".//key") %>% xml_text()          # get entry keys (column names)
        ) %>% 
          as.list() %>%                                      # turn named vector to list
          flatten_df() %>%                                   # and list to df
          mutate(ID = xml_attr(.x, "ID"))                    # add id
      }) %>%
      type_convert() %>% # let R convert the values for you
      select(ID, everything()) # get it in the order you likely want
    ## # A tibble: 2 x 5
    ##      ID TEST1 TEST2 TEST3 TEST4
    ##   <int> <chr> <int> <chr> <chr>
    ## 1   100  <NA>    12     A  <NA>
    ## 2   101  BLAH    NA  <NA>  <NA>
    

    【讨论】:

    • 效果很好,也适用于我的“真实”XML 数据!!非常感谢您提供可读的解决方案。 cmets 也很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    相关资源
    最近更新 更多