【问题标题】:Load XML to Dataframe in R with parent node attributes使用父节点属性将 XML 加载到 R 中的 Dataframe
【发布时间】:2015-03-03 07:35:26
【问题描述】:

我有一个 XML 文件(TEI 编码的播放),我想将它处理成 R 中的 data.frame,其中 data.frame 的每一行都包含播放的一行、行号、扬声器该行、场景编号和场景类型。 XML 文件的正文如下所示(但更长):

<text>
<body>
<div1 type="scene" n="1">
    <sp who="fau">
        <l n="30">Settle thy studies, Faustus, and begin</l>
        <l n="31">To sound the depth of that thou wilt profess;</l>
        <l n="32">Having commenced, be a divine in show,</l>
    </sp>
    <sp who="eang">
        <l n="105">Go forward, Faustus, in that famous art,</l>
    </sp>
</div1>
<div1 type="scene" n="2">
    <sp who="sch1">
        <l n="NA">I wonder what's become of Faustus, that was wont to make our schools ring with sic probo.</l>
    </sp>
    <sp who="sch2">
        <l n="NA">That shall we know, for see here comes his boy.</l>
    </sp>
    <sp who="sch1">
        <l n="NA">How now sirrah, where's thy master?</l>
    </sp>
    <sp who="wag">
        <l n="NA">God in heaven knows.</l>
    </sp>   
</div1>
</body>
</text>

这个问题似乎与herehere 提出的问题相似,但我的XML 文件的结构略有不同,因此两者都没有给我一个可行的解决方案。我已经做到了:

library(XML)
doc <- xmlTreeParse("data/faustus_sample.xml", useInternalNodes=TRUE)

bodyToDF <- function(x){
  scenenum <- xmlGetAttr(x, "n")
  scenetype <- xmlGetAttr(x, "type")
  attributes <- sapply(xmlChildren(x, omitNodeTypes = "XMLInternalTextNode"), xmlAttrs)
  linecontent <- sapply(xmlChildren(x), xmlValue)
  data.frame(scenenum = scenenum, scenetype = scenetype, attributes = attributes, linecontent = linecontent, stringsAsFactors = FALSE)
}

res <- xpathApply(doc, '//div1', bodyToDF)
temp.df <- do.call(rbind, res)

这会返回一个完整的“场景编号”、“场景类型”和“扬声器”的 data.frame,但我不知道如何将其分解为每一行(并获取相关的行号)。

我尝试将文件作为列表导入(通过 xmlToList),但这给了我一个非常混乱的列表列表,如果我尝试使用 for 循环访问不同的列表,也会导致许多不同的错误元素(可怕的想法,我知道!)。

理想情况下,我正在寻找一种解决方案,该解决方案既可以处理完整的文件,又可以处理其他类似结构的 XML 文件。

我刚刚开始使用 R,完全不知所措。非常感谢您提供的任何帮助。

感谢您的帮助!

编辑:完整 xml 文件的副本可用here

【问题讨论】:

    标签: xml r dataframe tei


    【解决方案1】:

    为 sp 元素添加了额外的 xpathApply:

    bodyToDF <- function(x){
      scenenum <- xmlGetAttr(x, "n")
      scenetype <- xmlGetAttr(x, "type")
      sp <- xpathApply(x, 'sp', function(sp) {
        who <- xmlGetAttr(sp, "who")
        if(is.null(who))
          who <- NA
        line_num <- xpathSApply(sp, 'l', function(l) { xmlGetAttr(l,"n")})
        linecontent = xpathSApply(sp, 'l', function(l) { xmlValue(l,"n")})
        data.frame( scenenum, scenetype, who, line_num, linecontent)
      })
      do.call(rbind, sp)  
    }
    
    res <- xpathApply(doc, '//div1', bodyToDF)
    temp.df <- do.call(rbind, res)
    

    前 4 列:

    # > temp.df[,1:4]
    #   scenenum scenetype  who line_num
    # 1        1     scene  fau       30
    # 2        1     scene  fau       31
    # 3        1     scene  fau       32
    # 4        1     scene eang      105
    # 5        2     scene sch1       NA
    # 6        2     scene sch2       NA
    # 7        2     scene sch1       NA
    # 8        2     scene  wag       NA
    

    【讨论】:

    • 事实证明这个解决方案非常适用于示例 xml,但会中断整个文档。据我所知,两者的格式相同。在运行res &lt;- xpathApply(doc, '//div1', bodyToDF) 行时,我收到错误"Error in data.frame(scenenum = xmlGetAttr(x, "n"), scenetype = xmlGetAttr(x, : arguments imply differing number of rows: 1, 0 "
    • 在完整文档中有一行没有who 属性。我更新了处理这种情况的答案(is.null(who))。
    • 是的,刚刚抓到了。仍然是一个 R 菜鸟,但我会掌握这个的。非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    相关资源
    最近更新 更多