HTML树解析处理程序的解释

4
XML包中的示例部分?htmlParse中,有以下函数getLinks()
getLinks <- function() { 
       links <- character() 
       list(a = function(node, ...) { 
                   links <<- c(links, xmlGetAttr(node, "href"))
                   node 
                }, 
            links = function()links)
     }

使用它一段时间后,再仔细观察,我仍然无法理解函数体中发生的事件顺序。

> bod <- as.list(body(getLinks))
> c(bod, rapply(bod, as.list))
[[1]]
`{`

[[2]]
links <- character()

[[3]]
list(a = function(node, ...) {
    links <<- c(links, xmlGetAttr(node, "href"))
    node
}, links = function() links)

$a
function (node, ...) 
{
    links <<- c(links, xmlGetAttr(node, "href"))
    node
}
<environment: 0x595f7f0>

$links
function () 
links
<environment: 0x595f7f0>

能否提供该函数中发生的事件链的详细解释?

如果需要示例,请运行以下代码:

> library(XML)
> URL <- "http://www.retrosheet.org/game.htm"
> h1 <- getLinks()
> htmlTreeParse(URL, handlers = h1)
> h1$links()
2个回答

8
在单独使用时,该函数并没有什么用处。它只有在与htmlTreeParse配合使用时才有用。它有两个作用。首先,它创建了一个闭包/环境,在此环境中收集链接向量。其次,它返回一个可用作htmlTreeParse中的handler=的列表。根据文档,处理程序是可选的函数集合,用于将不同的XML节点映射到R对象上。通常,这是一个命名函数集合列表,可以使用闭包提供本地数据。这提供了一种过滤在R中创建的树、添加或删除节点、以及通常在C代码中构造它们时进行处理的方法。
所以htmlTreeParse将在列表中查找与HTML文件中元素的节点名称相匹配的名称。因此,由于列表中有一个"a"元素,该函数将为文档中的每个<a>(链接)标签调用该函数。该函数简单地提取href属性,即URL存储的位置,并将其添加到闭包中的links数组中。
最后,在解析完成后,您需要一种方法来访问闭包内部的links向量。因此,该列表还定义了一个"links"元素。这是一个函数,只返回受保护的向量。您可以将此函数命名为任何名称,只要它与HTML文档中的标签名称不匹配即可。
因此,该getLinks()函数只返回一个可用作处理程序的列表。大部分真正的工作都是在htmlTreeParse函数中完成的。

谢谢您,非常好的解释。这个函数使得我所有的包函数都变得更快了。 - Rich Scriven

2
除了Flick先生的出色解释,这里提供一个简单的演示来展示这个函数是如何工作的:
 getLinks <- function() { 
  links <- character() 
  list(a = function(node, ...) { 
    links <<- c(links,  node)  ## I omit the call to XMLGetAttr
    node 
  }, 
  links = function()links)
}
h1 = getLinks()

现在我只需多次调用该函数,并在每次调用时打印结果链接:
for (i in 1:3 ){
  print(h1$links())
  h1$a(paste0("node",i))
}

正如您所看到的,链接只是一个列表,在每次调用 getlinks 时通过找到的新链接进行递增:

character(0)
[1] "node1"
[1] "node1" "node2"

基本上,它会尽可能深入HTML内容,或者需要深入到哪个程度。这真的很酷。这个XML东西真的很不可思议。 - Rich Scriven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接