将 xml-对象写入磁盘
Write xml-object to disk
我有一大堆 xml
文件需要处理。就此而言,我希望能够读取文件,并将生成的对象列表保存到磁盘。我试图用 readr::write_rds
保存列表,但再次读入后,对象有所修改,不再有效。我能做些什么来缓解这个问题吗?
library(readr)
library(xml2)
x <- read_xml("<foo>
<bar>text <baz id = 'a' /></bar>
<bar>2</bar>
<baz id = 'b' />
</foo>")
# function to save and read object
roundtrip <- function(obj) {
tf <- tempfile()
on.exit(unlink(tf))
write_rds(obj, tf)
read_rds(tf)
}
list(x)
#> [[1]]
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
roundtrip(list(x))
#> [[1]]
#> {xml_document}
identical(x, roundtrip(x))
#> [1] FALSE
all.equal(x, roundtrip(x))
#> [1] TRUE
xml_children(roundtrip(x))
#> Error in fun(x$node, ...): external pointer is not valid
as_list(roundtrip(x))
#> Error in fun(x$node, ...): external pointer is not valid
一些上下文
我有大约 500,000 个 xml 文件。为了处理它们,我计划将它们变成一个带有 xml2::as_list
的列表,并且我编写了代码来提取我需要的内容。后来我意识到,as_list
比 运行 贵很多。我可以:
- 重新编写已经仔细调试过的代码来直接解析数据(
xml_child
、xml_text
、...),或者
- 使用
as_list
.
为了加快no. 2 我可以 运行 它在另一台具有更多内核的机器上,但我想将单个文件传递给那台机器,因为收集和复制所有文件非常耗时。
xml2 对象具有外部指针,当您天真地对其进行序列化时,这些指针将变得无效。该包提供 xml_serialize()
和 xml_unserialize()
对象来为您处理这个问题。不幸的是,API 有点麻烦,因为 base::serialize()
和 base::unserialize()
假设连接是打开的。
library(xml2)
x <- read_xml("<foo>
<bar>text <baz id = 'a' /></bar>
<bar>2</bar>
<baz id = 'b' />
</foo>")
# function to save and read object
roundtrip <- function(obj) {
tf <- tempfile()
con <- file(tf, "wb")
on.exit(unlink(tf))
xml_serialize(obj, con)
close(con)
con <- file(tf, "rb")
on.exit(close(con), add = TRUE)
xml_unserialize(con)
}
x
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
(y <- roundtrip(x))
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
identical(x, y)
#> [1] FALSE
all.equal(x, y)
#> [1] TRUE
xml_children(y)
#> {xml_nodeset (3)}
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
as_list(y)
#> $bar
#> $bar[[1]]
#> [1] "text "
#>
#> $bar$baz
#> list()
#> attr(,"id")
#> [1] "a"
#>
#>
#> $bar
#> $bar[[1]]
#> [1] "2"
#>
#>
#> $baz
#> list()
#> attr(,"id")
#> [1] "b"
另外关于你问题的第二部分,我会认真考虑使用 XPATH 表达式来提取所需的数据,即使你必须重写代码。
我有一大堆 xml
文件需要处理。就此而言,我希望能够读取文件,并将生成的对象列表保存到磁盘。我试图用 readr::write_rds
保存列表,但再次读入后,对象有所修改,不再有效。我能做些什么来缓解这个问题吗?
library(readr)
library(xml2)
x <- read_xml("<foo>
<bar>text <baz id = 'a' /></bar>
<bar>2</bar>
<baz id = 'b' />
</foo>")
# function to save and read object
roundtrip <- function(obj) {
tf <- tempfile()
on.exit(unlink(tf))
write_rds(obj, tf)
read_rds(tf)
}
list(x)
#> [[1]]
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
roundtrip(list(x))
#> [[1]]
#> {xml_document}
identical(x, roundtrip(x))
#> [1] FALSE
all.equal(x, roundtrip(x))
#> [1] TRUE
xml_children(roundtrip(x))
#> Error in fun(x$node, ...): external pointer is not valid
as_list(roundtrip(x))
#> Error in fun(x$node, ...): external pointer is not valid
一些上下文
我有大约 500,000 个 xml 文件。为了处理它们,我计划将它们变成一个带有 xml2::as_list
的列表,并且我编写了代码来提取我需要的内容。后来我意识到,as_list
比 运行 贵很多。我可以:
- 重新编写已经仔细调试过的代码来直接解析数据(
xml_child
、xml_text
、...),或者 - 使用
as_list
.
为了加快no. 2 我可以 运行 它在另一台具有更多内核的机器上,但我想将单个文件传递给那台机器,因为收集和复制所有文件非常耗时。
xml2 对象具有外部指针,当您天真地对其进行序列化时,这些指针将变得无效。该包提供 xml_serialize()
和 xml_unserialize()
对象来为您处理这个问题。不幸的是,API 有点麻烦,因为 base::serialize()
和 base::unserialize()
假设连接是打开的。
library(xml2)
x <- read_xml("<foo>
<bar>text <baz id = 'a' /></bar>
<bar>2</bar>
<baz id = 'b' />
</foo>")
# function to save and read object
roundtrip <- function(obj) {
tf <- tempfile()
con <- file(tf, "wb")
on.exit(unlink(tf))
xml_serialize(obj, con)
close(con)
con <- file(tf, "rb")
on.exit(close(con), add = TRUE)
xml_unserialize(con)
}
x
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
(y <- roundtrip(x))
#> {xml_document}
#> <foo>
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
identical(x, y)
#> [1] FALSE
all.equal(x, y)
#> [1] TRUE
xml_children(y)
#> {xml_nodeset (3)}
#> [1] <bar>text <baz id="a"/></bar>
#> [2] <bar>2</bar>
#> [3] <baz id="b"/>
as_list(y)
#> $bar
#> $bar[[1]]
#> [1] "text "
#>
#> $bar$baz
#> list()
#> attr(,"id")
#> [1] "a"
#>
#>
#> $bar
#> $bar[[1]]
#> [1] "2"
#>
#>
#> $baz
#> list()
#> attr(,"id")
#> [1] "b"
另外关于你问题的第二部分,我会认真考虑使用 XPATH 表达式来提取所需的数据,即使你必须重写代码。