我在使用lapply
包中的xml_find_first
和xml2
来从xml对象列表中提取节点时出现问题。我从Scopus API中提取了几千条记录。由于我一次只能获得25条记录,因此我运行它以便获得包含100个元素的列表,每个元素包含25条记录。我知道有些记录缺少值,所以我的目标是随机播放,直到我得到一个列表,每个记录都是它自己的元素,然后使用lapply
和xml_find_first
以便我和#39 ; ll在适当的地方获取空值。问题是我最终会拉出重复的值,就好像所有内容仍然嵌套在它们的初始列表中一样。
这是一个可重复的示例,其中包含2个元素的列表,每个元素包含2个记录,最后一个缺少citedby-count
:
```{r}
library(xml2)
# Simulate how data come in from Scopus
# Build 2 list elements, 2 entries each
el1 <- read_xml(
"<feed>
<blah>Bunch of stuff I don't need</blah>
<blah>Bunch of other stuff I don't need</blah>
<entry>
<eid>2-s2.0-1542382496</eid>
<citedby-count>9385</citedby-count>
</entry>
<entry>
<eid>2-s2.0-0032721879</eid>
<citedby-count>4040</citedby-count>
</entry>
</feed>"
)
el2 <- read_xml( # This one's missing citedby-count for last entry
"<feed>
<blah>Bunch of stuff I don't need</blah>
<blah>Bunch of other stuff I don't need</blah>
<entry>
<eid>2-s2.0-0041751098</eid>
<citedby-count>3793</citedby-count>
</entry>
<entry>
<eid>2-s2.0-73449149291</eid>
</entry>
</feed>"
)
# Combine into list
lst <- list(el1,el2)
# Check
lst
```
这给了我:
我的目标是提取条目,使它们成为列表项。这样,xml_find_first
应该为缺少citedby-count
的条目添加空值。
```{r}
# Pull entry nodes
lst2 <- lapply(lst, xml_find_all, "//entry")
# Unlist
lst2 <- unlist(lst2, recursive=FALSE)
# Check - each entry is its own element
lst2
```
挂断是指当我尝试提取一些我知道在某些条目中缺少的节点时,会遗漏一个空缺的节点。 xml_find_first
应该这样做。但...
```{r}
cbc <- lapply(lst2, xml_find_first, "//citedby-count")
cbc <- lapply(cbc, xml_text)
cbc # Repeats the first values of original nesting
```
所以我检查了xml_find_all
会发生什么:
```{r}
cbc2 <- lapply(lst2, xml_find_all, "//citedby-count")
cbc2 <- lapply(cbc2, xml_text)
cbc2 # Elements contain all values from initial nesting
```
与上面lst2
的输出相比,没有任何意义。出于某种原因,拉动文本会保留初始嵌套中的值,即使在查看最终的xml对象列表时它也不会显示。我很难过。
答案 0 :(得分:1)
事实上,正如@ Dave2e评论的那样,不要简单地使用&#34;随时随地对于子元素,使用//
进行XPath搜索(特别是后代或自我搜索),因为搜索将在整个文档上运行。
如果我没有明确地调用原始文档,这怎么可能?如果您在任何 xml_find 列表上运行str()
,您将看到该对象带有Rcpp
指向当前节点的节点的外部指针文档可根据需要进行调用。实际上,我相信在调用列表时会显示 node 指针。
str(ls2)
# List of 4
# $ :List of 2
# ..$ node:<externalptr>
# ..$ doc :<externalptr>
# ..- attr(*, "class")= chr "xml_node"
# $ :List of 2
# ..$ node:<externalptr>
# ..$ doc :<externalptr>
# ..- attr(*, "class")= chr "xml_node"
# $ :List of 2
# ..$ node:<externalptr>
# ..$ doc :<externalptr>
# ..- attr(*, "class")= chr "xml_node"
# $ :List of 2
# ..$ node:<externalptr>
# ..$ doc :<externalptr>
# ..- attr(*, "class")= chr "xml_node"
lst2[[1]]$doc
# <pointer: 0x000000000ca7ff90>
typeof(lst2[[1]]$doc)
# [1] "externalptr"
因此,搜索时请注意上下文。您可以使用点前缀(如@ Dave2e建议),.//
或根本没有斜杠来检索子元素,这些元素在这里是等效的。
cbc2 <- lapply(lst2, xml_find_all, "citedby-count")
cbc2 <- lapply(cbc2, xml_text)
cbc2
# [[1]]
# [1] "9385"
# [[2]]
# [1] "4040"
# [[3]]
# [1] "3793"
# [[4]]
# character(0)
cbc2 <- lapply(lst2, xml_find_all, ".//citedby-count")
cbc2 <- lapply(cbc2, xml_text)
cbc2
# [[1]]
# [1] "9385"
# [[2]]
# [1] "4040"
# [[3]]
# [1] "3793"
# [[4]]
# character(0)
请注意.//
将搜索从当前节点开始的所有后代(即子孙,孙子等)。见What is the difference between .// and //* in XPath?