为了进行一些分析,我想使用 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>
我想让数据框的行包含以下字段:
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
开头缺失,“结果”放在“结果”列下的字符串中。
一定有可能获得想要的数据框,但我不知道如何准确地做到这一点。
更新
@MvG 提供的解决方案在上述测试 XML 文件上表现出色。但是,“结果”列也可以具有值“未找到”。具有此值的条目将丢失某些字段(始终是相同的字段),因此会产生“参数列数不匹配”- 运行解决方案时出现错误。我也希望将这些条目也放入数据框中,不存在的字段留空。我不明白如何合并这种情况。
test.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>
<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>
最佳答案
这是一个更通用的方法。每个节点都被归类为三种情况之一:
rows,那么来自子节点的数据帧将导致结果的不同行。cols类型,那么来自子节点的数据帧将导致结果的不同列。值类型,则将构造一个具有单个值的数据框,使用节点名称作为列名称,节点值作为列值。您的申请电话在底部。
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), xml2df, 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")
})
关于xml - 将 XML 的所有字段(和子字段)导入为数据框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12421668/
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否