R XML 计算每个节点 x 的子节点

标签 r xml performance xpath

我有一个带有 PropertyItemData 节点的大型 XML,其中可以包含 ObjectList 节点。 我想获取每个 PropertyItemData 的 ObjectList 子节点计数的列表/向量。

示例数据的生成:

doc <-
'
<a>
<PropertyItemData>
  <ObjectList>
    <ObjectData><z>1</z></ObjectData>
  </ObjectList>
</PropertyItemData>
<PropertyItemData>
  <ObjectList>
    <ObjectData><z>1</z></ObjectData>
    <ObjectData><z>1</z></ObjectData>
  </ObjectList>
</PropertyItemData>
<PropertyItemData>
</PropertyItemData>
</a>
'

n <- 300 * 1000
doc2 <- paste(lapply(1:n, function(x) doc), collapse = '')
doc2 <- sprintf('<b>%s</b>', doc2)

当前方法:

library(XML)
xx <- xmlParse(doc2)
b <-  getNodeSet(xx, "//PropertyItemData") # get all PropertyItemData
s2 <- sapply(b, xpathSApply, ".//ObjectList", xmlSize) # for each count ObjectList sub-nodes
s2[lengths(s2) == 0L] <- 0L # if no subnodes = 0
s2 <- unlist(s2)
head(s2)
# [1] 1 2 0 1 2 0

有没有更快的方法来获得想要的结果?这可以用 XPath 完成吗?

最佳答案

此替代方案可将您的数据处理时间缩短 80% 以上。

library(xml2)
n <- 300 * 1000 
doc2 <- paste(lapply(1:n, function(x) doc), collapse = '')
doc2 <- sprintf('<b>%s</b>', doc2)

xx2 <- read_xml(doc2)
b2 <- xml_find_all(xx2, "//PropertyItemData")

result <- sapply(b2, function(y) xml_length(xml_children(y)))
identical(result, s2)
# [1] TRUE

基准测试

original_sol <- function(){
  xx <- xmlParse(doc2)
 b <-  getNodeSet(xx, "//PropertyItemData")
s2 <- sapply(b, xpathSApply, ".//ObjectList", xmlSize)
s2[lengths(s2) == 0L] <- 0L
s2 <- unlist(s2)
}
new_sol <- function(){
  xx2 <- read_xml(doc2)
  b2 <- xml_find_all(xx2, "//PropertyItemData")
  result <- sapply(b2, function(y) xml_length(xml_children(y)))
}

library(microbenchmark)
microbenchmark(
  original_solution = original_sol(),
  new_solution = new_sol(),
  times=1
)
Unit: seconds
              expr       min        lq      mean    median        uq       max neval
 original_solution 120.47773 120.47773 120.47773 120.47773 120.47773 120.47773     1
      new_solution  25.35973  25.35973  25.35973  25.35973  25.35973  25.35973     1

编辑 如果您需要比计算 PropertyItemData 节点的所有子节点更具体的方法,这里有 2 个其他方法:

  • 与您使用的算法相同(列出 ObjectList 节点的子节点),
  • 对子 ObjectData 节点进行计数。
# same method as OP's: length of children of ObjectList nodes -------------
objectlist <- lapply(b2, function(x) xml_find_all(x, "ObjectList"))
result_same_algorithm <- sapply(objectlist, function(x) sum(xml_length(xml_children(x))))
identical(result_same_algorithm, s2)
# third possibility: length of Object data children nodes --------------------------
res_objectdata_children <- sapply(b2, function(x) sum(xml_length(xml_find_all(x, ".//ObjectData"))))
identical(res_objectdata_children, s2)

关于R XML 计算每个节点 x 的子节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73222986/

相关文章:

r - 快速检查 Rcpp 中的缺失值

r - 将多个列合并为一个具有 R 中特定条件的列

java - Android:工作线程完成工作后如何执行回调

JavaFX 允许用户仅编辑文本的某些区域

javascript - ember 核心表单组件中的 ARIA 属性

c++ - 从午夜开始获取纳秒级的最低延迟

R:使用ROCR绘制多条不同颜色的ROC曲线

html - 使用 rvest 跟随 "next"与相对路径的链接

r - 如何将所有 NA 的行求和为 0/NA

java - 将 Hl7 消息转换为 Json