R中的XML:多个没有循环的同名子级

时间:2019-10-21 18:46:44

标签: r xml xpath xml2

我有一个XML文档,如下所示:

<root>
    <Item>
        <A>text1</A>
        <B>text2</B>
        <C>text3</C>
        <C>text4</C>
        <C>text5</C>
        <D>text6</D>
        ...
    </Item>
    <Item>
        ...
    </Item>
    ...
</root>

有一个复杂因素,它相对简单:每个item可以有任意数量的C

最终,我希望将其放在一个表中,例如:

  A     B     C          D    
1 text1 text2 <list [3]> text6

我已经为其他变量创建了表格(可能是一种混乱的方式,但是它可以工作):

vnames<-c("A","B","D")
dat<-list()
for(i in 1:length(vnames)){
    dat[[i]]<-xml_text(xml_find_first(nodeset,paste0(".//d1:",vnames[[i]]),xml_ns(xmlfile)))
}
dat<-as.data.frame(dat,col.names=vnames)

但是这种方法仅在xml_find_first确实为您提供所需的一切时才有效。我可以使用xml_find_all,但这会使列表长度对于合并而言是不相等的。我有一长串C的清单,但我不知道哪一个附有哪个项目。

我当然可以遍历每个项目和xml_find_allC,但这似乎效率很低。有没有更简单的方法可以做到这一点?

很抱歉是否已被问到;我找不到另外,我是XML的新手,因此可能需要一种全新的方法。谢谢!

1 个答案:

答案 0 :(得分:1)

这是一个可能的解决方案,我不确定最终结果是否就是您想要的。

如果所有数据仅下一层,则此方法效果很好。如果数据在xml中向下存储了多个级别,则需要扩展此解决方案。基本方法是解析所有Item节点。从每个项目节点中的所有子节点收集信息,然后通过计算每个项目中的孩子数来创建项目索引。然后将所有数据存储在3列数据框中:ItemIndex,子名称和值。从这里开始,只需转换为所需的最终格式即可。

library(xml2)

page<-read_xml("<root>
    <Item>
        <A>text1</A>
        <B>text2</B>
        <C>text3</C>
        <C>text4</C>
        <C>text5</C>
        <D>text6</D>
    </Item>
    <Item>
        <A>text12</A>
        <B>text22</B>
        <C>text32</C>
    </Item>
</root>")

#find all items and store as a list
items<-xml_find_all(page, ".//Item")

#extract all children's names and values 
nodenames<-xml_name(xml_children(items))
contents<-trimws(xml_text(xml_children(items)))

#Need to create an index to associate the nodes/contents with each item
itemindex<-rep(1:length(items), times=sapply(items, function(x) {length(xml_children(x))}))

#store all information in data frame.
df<-data.frame(itemindex, nodenames, contents)

#Convert from long to wide format
library(tidyr)
pivot_wider(df, id_cols= itemindex, names_from = nodenames,
            values_from = contents)  # %>% unnest(cols = c(A, B, C, D))

# A tibble: 2 x 5
itemindex       A           B           C           D
<int> <list<fct>> <list<fct>> <list<fct>> <list<fct>>
    1         [1]         [1]         [3]         [1]
    2         [1]         [1]         [1]         [0]