如何在不使用 xml2 R 包循环的情况下更新 xml 属性
How to update xml attributes without using a loop with the xml2 R package
我有一个 xml 对象,我想使用 R 的 xml2 包更新它。我通常需要做两件事:
- 更新节点内的文本
<c>{text}</c>
- 更新节点属性
<c name={text}/>
我想避免遍历 xml 结构,因为这比识别节点集并立即为其分配整个值向量要慢得多。
xml <- read_xml("<root>
<c name='test' db_name='TEST'><d>This is the column desc</d></c>
<c name='test2' db_name='TEST2'><d>This is the column desc</d></c>
<c name='test3' db_name='TEST3'><d>This is the column desc</d></c>
</root>")
df <- data.frame(
db_name = c("TEST2", "TEST", "TEST3"),
desc = c("New desc!", "You want this desc", "GOOD VECTOR"),
disp_name = c("OKAY", "NOW", "HAPPY"), stringsAsFactors = F)
#1 我们表现不错
c_nodes <- xml %>% xml_find_all("//c")
c_db_names <- c_nodes %>% xml_find_all("@db_name") %>% xml_text
xml_text(c_nodes) <- df$desc[match(c_db_names, df$db_name)]
#2 不好
disp_names <- df$disp_name[match(c_db_names, df$db_name)]
for (i in seq_along(c_nodes)) {
xml_attr(c_nodes[i], "name") <- disp_names[i]
}
当我尝试 xml_attr(c_nodes, "name") <- df$disp_name[match(c_db_names, df$db_name)]
时,出现以下错误:
Error in node_set_attr(x$node, name = attr, nsMap = ns, value) :
expecting a single value
如果我提供单个值,它会使用该值更新整个节点集,但我需要对每个节点属性进行不同的更新。因此,我正在使用一个循环,但我想用一个矢量化的等价物替换它来产生这个:
{xml_document}
<root>
[1] <c name="NOW" db_name="TEST">\n <d>You want this desc</d>\n</c>
[2] <c name="OKAY" db_name="TEST2">\n <d>New desc!</d>\n</c>
[3] <c name="HAPPY" db_name="TEST3">\n <d>GOOD VECTOR</d>\n</c>
xml_set_attrs 是要使用的正确函数,但您必须为值参数传入命名字符向量列表。您可以使用 apply 函数创建此列表,然后将其传递给函数,如下所示:
new_attrs<-lapply(df$disp_name[match(c_db_names, df$db_name)],
function(x) {
names(x)<- "name"
x
})
xml_set_attrs(c_nodes, new_attrs)
我有一个 xml 对象,我想使用 R 的 xml2 包更新它。我通常需要做两件事:
- 更新节点内的文本
<c>{text}</c>
- 更新节点属性
<c name={text}/>
我想避免遍历 xml 结构,因为这比识别节点集并立即为其分配整个值向量要慢得多。
xml <- read_xml("<root>
<c name='test' db_name='TEST'><d>This is the column desc</d></c>
<c name='test2' db_name='TEST2'><d>This is the column desc</d></c>
<c name='test3' db_name='TEST3'><d>This is the column desc</d></c>
</root>")
df <- data.frame(
db_name = c("TEST2", "TEST", "TEST3"),
desc = c("New desc!", "You want this desc", "GOOD VECTOR"),
disp_name = c("OKAY", "NOW", "HAPPY"), stringsAsFactors = F)
#1 我们表现不错
c_nodes <- xml %>% xml_find_all("//c")
c_db_names <- c_nodes %>% xml_find_all("@db_name") %>% xml_text
xml_text(c_nodes) <- df$desc[match(c_db_names, df$db_name)]
#2 不好
disp_names <- df$disp_name[match(c_db_names, df$db_name)]
for (i in seq_along(c_nodes)) {
xml_attr(c_nodes[i], "name") <- disp_names[i]
}
当我尝试 xml_attr(c_nodes, "name") <- df$disp_name[match(c_db_names, df$db_name)]
时,出现以下错误:
Error in node_set_attr(x$node, name = attr, nsMap = ns, value) :
expecting a single value
如果我提供单个值,它会使用该值更新整个节点集,但我需要对每个节点属性进行不同的更新。因此,我正在使用一个循环,但我想用一个矢量化的等价物替换它来产生这个:
{xml_document}
<root>
[1] <c name="NOW" db_name="TEST">\n <d>You want this desc</d>\n</c>
[2] <c name="OKAY" db_name="TEST2">\n <d>New desc!</d>\n</c>
[3] <c name="HAPPY" db_name="TEST3">\n <d>GOOD VECTOR</d>\n</c>
xml_set_attrs 是要使用的正确函数,但您必须为值参数传入命名字符向量列表。您可以使用 apply 函数创建此列表,然后将其传递给函数,如下所示:
new_attrs<-lapply(df$disp_name[match(c_db_names, df$db_name)],
function(x) {
names(x)<- "name"
x
})
xml_set_attrs(c_nodes, new_attrs)