我有一个大的XML文件,我需要用xmlEventParse in R进行解析。不幸的是,在线示例比我需要的更复杂,我只想标记一个匹配的节点标签来存储匹配的节点文本(不是属性),每个文本都在一个单独的列表中,请参阅下面代码中的注释:
library(XML)
z <- xmlEventParse(
"my.xml",
handlers = list(
startDocument = function()
{
cat("Starting document\n")
},
startElement = function(name,attr)
{
if ( name == "myNodeToMatch1" ){
cat("FLAG Matched element 1\n")
}
if ( name == "myNodeToMatch2" ){
cat("FLAG Matched element 2\n")
}
},
text = function(text) {
if ( # Matched element 1 .... )
# Store text in element 1 list
if ( # Matched element 2 .... )
# Store text in element 2 list
},
endDocument = function()
{
cat("ending document\n")
}
),
addContext = FALSE,
useTagName = FALSE,
ignoreBlanks = TRUE,
trim = TRUE)
z$ ... # show lists ??
我的问题是,如何在R中实现这个标志(以专业的方式:)? 另外:评估N个任意节点以匹配的最佳选择...如果name =“myNodeToMatchN”......节点避免大小写匹配?
my.xml可能只是一个像
这样的天真XML<A>
<myNodeToMatch1>Text in NodeToMatch1</myNodeToMatch1>
<B>
<myNodeToMatch2>Text in NodeToMatch2</myNodeToMatch2>
...
</B>
</A>
答案 0 :(得分:8)
我将使用fileName
中的example(xmlEventParse)
作为可重现的示例。它的标记record
具有属性id
和我们想要提取的文本。我将继续使用handler
参数,而不是使用branches
。这就像一个处理程序,但是可以访问整个节点而不仅仅是元素。我们的想法是编写一个闭包,它有一个位置来保存我们积累的数据,以及一个处理我们感兴趣的XML文档的每个分支的函数。所以让我们首先定义闭包 - 为了我们的目的,一个函数,返回函数列表
ourBranches <- function() {
我们需要一个地方来存储我们积累的结果,选择一个环境以便插入时间是恒定的(不是列表,我们必须附加到它并且内存效率低)
store <- new.env()
事件解析器期望在发现匹配标记时调用函数列表。我们对record
标记感兴趣。我们编写的函数将接收XML文档的节点。我们想要提取一个元素id
,我们将用它来存储节点中的(文本)值。我们将这些添加到我们的商店。
record <- function(x, ...) {
key <- xmlAttrs(x)[["id"]]
value <- xmlValue(x)
store[[key]] <- value
}
处理完文档后,我们想要一种方便的方法来检索我们的结果,因此我们为自己的目的添加一个函数,与文档中的节点无关
getStore <- function() as.list(store)
然后返回一个函数列表
来完成闭包 list(record=record, getStore=getStore)
}
这里一个棘手的概念是定义函数的环境是函数的一部分,因此每次我们说ourBranches()
时我们都会得到一个函数列表和一个新的环境store
保持我们的结果。要使用,请在我们的文件上调用xmlEventParse
,使用一组空的事件处理程序,然后访问我们累积的商店。
> branches <- ourBranches()
> xmlEventParse(fileName, list(), branches=branches)
list()
> head(branches$getStore(), 2)
$`Hornet Sportabout`
[1] "18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 "
$`Toyota Corolla`
[1] "33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 "
答案 1 :(得分:2)
对于其他可能尝试向M.Morgan学习的人 - 这是完整的代码
fileName = system.file("exampleData", "mtcars.xml", package = "XML")
ourBranches <- function() {
store <- new.env()
record <- function(x, ...) {
key <- xmlAttrs(x)[["id"]]
value <- xmlValue(x)
store[[key]] <- value
}
getStore <- function() as.list(store)
list(record=record, getStore=getStore)
}
branches <- ourBranches()
xmlEventParse(fileName, list(), branches=branches)
head(branches$getStore(), 2)
答案 2 :(得分:0)
branches方法不保留事件的顺序。换句话说,&#39;记录的顺序&#39;在branches中,$ getStore()存储与原始xml文件中的存储不同。另一方面,处理程序方法可以保留顺序。这是代码:
fileName <- system.file("exampleData", "mtcars.xml", package="XML")
records <- new('list')
variable <- new('character')
tag.open <- new('character')
nvar <- 0
xmlEventParse(fileName, list(startElement = function (name, attrs) {
tagName <<- name
tag.open <<- c(name, tag.open)
if (length(attrs)) {
attributes(tagName) <<- as.list(attrs)
}
}, text = function (x) {
if (nchar(x) > 0) {
if (tagName == "record") {
record <- list()
record[[attributes(tagName)$id]] <- x
records <<- c(records, record)
} else {
if( tagName == 'variable') {
v <- x
variable <<- c( variable, v)
nvar <<- nvar + 1
}
}
}
}, endElement = function (name) {
if( name == 'record') {
print(paste(tag.open, collapse='>'))
}
tag.open <<- tag.open[-1]
}))
head(records,2)
$``Mazda RX4``
[1] "21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4"
$`Mazda RX4 Wag`
[1] "21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4"
variable
[1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear" "carb"
使用处理程序的另一个好处是可以捕获分层结构。换句话说,也可以保存祖先。此过程的关键点之一是使用全局变量,可以使用&#34;&lt;&lt; - &#34;而不是&#34;&lt; - &#34;。