将XML的所有字段(和子字段)导入为dataframe
为了做一些分析,我想使用R和
XML包将
XML导入数据帧.
XML文件示例:
<watchers shop_name="TEST" created_at="September 14,2012 05:44"> <watcher channel="Site Name"> <code>123456</code> <search_key>TestKey</search_key> <date>September 14,2012 04:15</date> <result>Found</result> <link>http://www.test.com/fakeurl</link> <price>100.0</price> <shipping>0.0</shipping> <origposition>0</origposition> <name>Name Test</name> <results> <result position="1"> <c_name>CTest1</c_name> <c_price>599.49</c_price> <c_shipping>0.0</c_shipping> <c_total_price>599.49</c_total_price> <c_rating>8.3</c_rating> <c_delivery/> </result><result position="2"> <c_name>CTest2</c_name> <c_price>654.0</c_price> <c_shipping>0.0</c_shipping> <c_total_price>654.0</c_total_price> <c_rating>9.8</c_rating> <c_delivery/> </result> <result position="3"> <c_name>CTest3</c_name> <c_price>654.0</c_price> <c_shipping>0.0</c_shipping> <c_total_price>654.0</c_total_price> <c_rating>8.8</c_rating> <c_delivery/> </result> </results> </watcher> </watchers> 我想让dataframe的行包含以下字段: shop_name created_at code search_key date result link price shipping origposition name position c_name c_price c_shipping c_total_price c_rating c_delivery 这意味着必须考虑子节点,这将导致本例中的三行数据帧(因为结果显示3个位置).田野 shop_name created_at code search_key date result link price shipping origposition name 对于这些行中的每一行都是相同的. 我能够浏览XML文件,但我无法获得包含我想要的字段的数据框.当我将数据帧转换为数据帧时,我得到以下字段: "code" "search_key" "date" "result" "link" "price" "shipping" "origposition" "name" "results" 在这里的领域 shop_name created_at 在开头缺少’结果’并在“结果”列下的字符串中放在一起. 必须有可能得到想要的数据帧,但我不知道如何准确地做到这一点. UPDATE @MvG提供的解决方案在上面提到的测试XML文件上运行得非常出色.但是,“结果”列也可以具有“未找到”值.具有此值的条目将丢失某些字段(始终是相同的字段),因此在运行解决方案时会产生“参数列数不匹配”-error.我希望这些条目也放在数据框中,不存在的字段留空.我不明白如何合并这个场景. 的test.xml <watchers shop_name="TEST" created_at="September 14,2012 04:15</date> <result>Found</result> <link>http://www.test.com/fakeurl</link> <price>100.0</price> <shipping>0.0</shipping> <origposition>0</origposition> <name>Name Test</name> <results> <result position="1"> <c_name>CTest1</c_name> <c_price>599.49</c_price> <c_shipping>0.0</c_shipping> <c_total_price>599.49</c_total_price> <c_rating>8.3</c_rating> <c_delivery/> </result><result position="2"> <c_name>CTest2</c_name> <c_price>654.0</c_price> <c_shipping>0.0</c_shipping> <c_total_price>654.0</c_total_price> <c_rating>9.8</c_rating> <c_delivery/> </result> <result position="3"> <c_name>CTest3</c_name> <c_price>654.0</c_price> <c_shipping>0.0</c_shipping> <c_total_price>654.0</c_total_price> <c_rating>8.8</c_rating> <c_delivery/> </result> </results> </watcher> <watcher channel="Shopping"> <code>12804</code> <search_key></search_key> <date></date> <result>Not found</result> <link>https://www.test.com/testing1323p</link> <price>0.0</price> <shipping>0.0</shipping> <origposition>0</origposition> <name>MOOVM6002020</name> <results> </results> </watcher> </watchers> 解决方法
这是一种更通用的方法.每个节点都被归类为三种情况之一:
>如果节点名称是种类行,则子节点的数据帧将导致结果的不同行. 您的申请要求在底部. library(XML) zeroColSingleRow <- function() { res <- data.frame(dummy=NA) res$dummy <- NULL stopifnot(nrow(res) == 1,ncol(res) == 0) return (res) } xml2df <- function(node,classifier) { if (! inherits(node,c("XMLInternalElementNode","XMLElementNode"))) { return (zeroColSingleRow()) } kind <- classifier(node) if (kind == "rows") { cdf <- lapply(xmlChildren(node),xml2df,classifier) if (length(cdf) == 0) { res <- zeroColSingleRow() } else { names <- unique(unlist(lapply(cdf,colnames))) cdf <- lapply(cdf,function(i) { missing <- setdiff(names,colnames(i)) if (length(missing) > 0) { i[missing] <- NA } return (i) }) res <- do.call(rbind,cdf) } } else if (kind == "cols") { cdf <- lapply(xmlChildren(node),classifier) if (length(cdf) == 0) { res <- zeroColSingleRow() } else { res <- cdf[[1]] if (length(cdf) > 1) { for (i in 2:length(cdf)) { res <- merge(res,cdf[[i]],by=NULL) } } } } else { stopifnot(kind == "value") res <- data.frame(xmlValue(node)) names(res) <- xmlName(node) } if (ncol(res) == 0) { res <- zeroColSingleRow() } attr <- xmlAttrs(node) if (length(attr) > 0) { attr <- do.call(data.frame,as.list(attr)) res <- merge(attr,res,by=NULL) } rownames(res) <- NULL return(res) } doc<-xmlParse("test.xml") xml2df(xmlRoot(doc),function(node) { name <- xmlName(node) if (name %in% c("watchers","results")) return("rows") # make sure to treat results/result different from watcher/result if (name %in% c("watcher","result") && xmlName(xmlParent(node)) == paste0(name,"s")) return("cols") return("value") }) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |