我一直在与这个斗争已经很长时间了,无法让它发挥作用,所以我在这里发帖。我不是一个高级的R用户,但我正在学习并慢慢地前进。我还没有找到Stackoverflow的一个例子,我可以适应这个,示例似乎有不同的结构,不需要遍历每个节点的每个更高级别的属性。或者这就是我现在理解差异的方式。问题类似于this,但文件结构不同。现在我基本上使用了this example。
假设我有大量的小型XML文件,其结构如下所示。它们的名称类似于file1.xml,file2.xml等。所以file1.xml将是:
<NODE>
<SUBNODE TYPE="WORDS" SPEAKER="person1">
<WORD>word1</WORD>
<WORD>word2</WORD>
<WORD>word3</WORD>
</SUBNODE>
<SUBNODE TYPE="WORDS" SPEAKER="person2">
<WORD>word4</WORD>
<WORD>word5</WORD>
<WORD>word6</WORD>
</SUBNODE>
</NODE>
然后file2.xml将是:
<NODE>
<SUBNODE TYPE="WORDS" SPEAKER="person3">
<WORD>word7</WORD>
<WORD>word8</WORD>
<WORD>word9</WORD>
</SUBNODE>
<SUBNODE TYPE="WORDS" SPEAKER="person4">
<WORD>word10</WORD>
<WORD>word11</WORD>
<WORD>word12</WORD>
</SUBNODE>
</NODE>
我想把它们变成这样的数据框:
Filename Speaker Word
file1 person1 word1
file1 person1 word2
file1 person1 word3
file1 person2 word4
file1 person2 word5
file1 person2 word6
file2 person3 word7
file2 person3 word8
file2 person3 word9
file2 person4 word10
file2 person4 word11
file2 person4 word12
我可以将所有单词列表合并到一个数据框中:
library(XML)
library(plyr)
xmlfiles <- list.files(pattern = "*.xml")
dat <- ldply(seq(xmlfiles), function(i){
doc <- xmlTreeParse(xmlfiles[i], useInternal = TRUE)
Word <- xpathSApply(doc, "//SUBNODE[@TYPE='WORDS']/WORD", xmlValue)
return(data.frame(Word))
})
“dat”的内容现在应该是单词列表。但无论我尝试什么,我都无法将其他数据添加到其中。我试图在那里添加像:
xmlfiles <- list.files(pattern = "*.xml")
dat <- ldply(seq(xmlfiles), function(i){
doc <- xmlTreeParse(xmlfiles[i], useInternal = TRUE)
Word <- xpathSApply(doc, "//SUBNODE[@TYPE='WORDS']/WORD", xmlValue)
Speaker <- xpathSApply(doc, "//SUBNODE[@TYPE='WORDS']", xmlGetAttr, "SPEAKER")
return(data.frame(Word, Speaker))
})
但是数据帧不正确,因为它没有将正确的发言者与正确的单词联系起来。
Word Speaker
word1 person1
word2 person2
word3 person1
word4 person2
word5 person1
word6 person2
word7 person3
word8 person4
word9 person3
word10 person4
word11 person3
word12 person4
然后我也经常遇到如下错误:
"Error in UseMethod("xmlValue") :
no applicable method for 'xmlValue' applied to an object of class "c('XMLInternalDocument', 'XMLAbstractDocument')"
或者我得到一个错误,这些错误的长度不同,当然,因为扬声器的数量少于单词。我尝试了很多东西,但我在这里只发布了“最成功”的方法。我知道我需要一个函数,将每个单词与上述节点中的speaker属性相匹配,只是将它们提取到自己的列表中没有帮助,我想现在这只是运气,在这个例子中是扬声器的数量和单词是匹配的,所以它们就像上面的数据框一样放在一起。
然后我仍然需要将文件名放到一列中,因为它们包含一些我在XML文件本身内部没有的信息。无论如何,这是我问题中最不重要的方面。我使用的实际文件要复杂得多,这就是为什么我在文件中有一些不必要的结构,如SUBNODE TYPE等。
感谢您的帮助!
答案 0 :(得分:3)
我可能会尝试循环遍历文件并解析getNodeSet。我不经常使用ldply,但你可以用那个替换循环吗?
xmlfiles <- list.files(pattern = "*.xml")
n <- length(xmlfiles)
dat <- vector("list", n)
for(i in 1:n){
doc <- xmlParse(xmlfiles[i])
nodes <- getNodeSet(doc, "//SUBNODE")
x<- lapply(nodes, function(x){ data.frame(
Filename = xmlfiles[i],
Speaker= xpathSApply(x, "." , xmlGetAttr, "SPEAKER"),
Word= xpathSApply(x, ".//WORD" , xmlValue) )})
dat[[i]] <- do.call("rbind", x)
}
do.call("rbind", dat)
答案 1 :(得分:2)
一种可能性是获取所有相关值(xml
是我认为您的doc
)
x = xml['//SUBNODE/@SPEAKER | //SUBNODE/WORD/text()']
找到扬声器并将所有内容转换为简单的字符向量
isSpeaker = sapply(x, is, "XMLAttributeValue")
x[!isSpeaker] = sapply(x[!isSpeaker], xmlValue)
x = unlist(x, use.names=FALSE)
然后捣乱结果
r = rle(isSpeaker)
data.frame(Speaker=rep(x[isSpeaker], r$length[!r$value]), Word=x[!isSpeaker])
(我不认为这对没有言语的发言者来说是健壮的,但那会是什么样的发言者?)