从 R 列表生成 xml

Posted

技术标签:

【中文标题】从 R 列表生成 xml【英文标题】:Generate a xml from a R list 【发布时间】:2022-01-03 17:32:15 【问题描述】:

我是 xml 新手并在 R 中处理它。

我已经能够使用 xml2 包从 xml 文件中读取和检索信息,但事实证明,从 R 对象创建 xml 文件更具挑战性。

特别是,我想从 R 列表生成一个 xml 文件。考虑下面的例子:

library(reprex)
library(xml2)

r_list <- list(person1 = list(starts = letters[1:3], ends = letters[4:6]), person2 = list(starts = LETTERS[1:4], ends = LETTERS[5:8]))
str(r_list)
#> List of 2
#>  $ person1:List of 2
#>   ..$ starts: chr [1:3] "a" "b" "c"
#>   ..$ ends  : chr [1:3] "d" "e" "f"
#>  $ person2:List of 2
#>   ..$ starts: chr [1:4] "A" "B" "C" "D"
#>   ..$ ends  : chr [1:4] "E" "F" "G" "H"

test1 <- xml2::as_xml_document((r_list))
#> Error: Root nodes must be of length 1

new_xml <- xml_new_root(.value = "category", name = "personList")

for(person in names(r_list))
  xml_add_child(new_xml, as_xml_document(r_list[person]))


new_xml
#> xml_document
#> <category name="personList">
#> [1] <person1>ad</person1>
#> [2] <person2>AE</person2>

由reprex package (v2.0.1) 于 2021 年 11 月 25 日创建

我尝试使用 as_xml_document 函数直接将列表强制转换为 xml,但出现错误 Root nodes must be of length 1

按照this question 上的想法,我尝试使用根节点和xml_add_child() 创建该文档的xml 文档,但没有得到预期的结果(参见代码输出)。在那个问题中,它们是从 R 数据框而不是列表转换而来的。

我还想拥有个性化的标签名称并为这些标签添加属性。期望的输出是:

<category name="personList">
    <pers name="person1">
        <starts>
            <value>a</value>
            <value>b</value>
            <value>c</value>
        </starts>
        <ends>
            <value>d</value>
            <value>e</value>
            <value>f</value>
        </ends>
    </pers>
    <pers name="person2">
        <starts>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>D</value>
        </starts>
        <ends>
            <value>D</value>
            <value>E</value>
            <value>F</value>
            <value>G</value>
        </ends>
    </pers>
</category>

感谢您的帮助,祝您有愉快的一天

【问题讨论】:

这能回答你的问题吗? How to create xml from R objects, e.g., is there a 'listToXml' function? 嗨@Limey,感谢您的快速回复。该链接非常有用,我设法使用newXMLNode 函数生成了所需的输出。然而,它需要嵌套的 for 循环来恢复列表的每个元素。作为开放性问题,您知道更好的解决方案吗?或xml2 包中的等价物? 【参考方案1】:

R 列表属性可以映射到 XML 属性:

library(xml2)
library(tidyverse)

r_list <- list(person1 = list(starts = letters[1:3], ends = letters[4:6]), person2 = list(starts = LETTERS[1:4], ends = LETTERS[5:8]))
r_list

new_xml <- xml_new_root(.value = "category", name = "personList")

for (person in names(r_list)) 
  p <- list()
  p[["pers"]] <- list(
    starts = r_list[[person]]$starts %>% map(~list(value = list(.x))),
    ends = r_list[[person]]$ends %>% map(~list(value = list(.x)))
  )
  attr(p[["pers"]], "name") <- person
  
  xml_add_child(new_xml, as_xml_document(p))


write_xml(new_xml, "foo.xml")

输出:

<?xml version="1.0" encoding="UTF-8"?>
<category name="personList">
  <pers name="person1">
    <starts>
      <value>a</value>
      <value>b</value>
      <value>c</value>
    </starts>
    <ends>
      <value>d</value>
      <value>e</value>
      <value>f</value>
    </ends>
  </pers>
  <pers name="person2">
    <starts>
      <value>A</value>
      <value>B</value>
      <value>C</value>
      <value>D</value>
    </starts>
    <ends>
      <value>E</value>
      <value>F</value>
      <value>G</value>
      <value>H</value>
    </ends>
  </pers>
</category>

【讨论】:

嗨@danlooo,感谢您的回答。我一直在尝试您的建议,但我无法正确获得 a ...。如果我理解正确,列表名称(用p[["pers"]] &lt;- list() 定义定义xml 标签,属性name 在xml 中设置标签属性,但我无法让它在循环中工作 @symduk 我修改了我的答案。但是,这种类型的 xml 序列化效率非常低,可以用更少的嵌套来完成。 感谢您的更新,您的代码会产生预期的结果(我需要一些时间来理解每一行)。为了完整起见,我将使用 Limey 建议的方法添加答案,但将接受的答案归于您。祝你有美好的一天!【参考方案2】:

根据@Limey 的评论(查看this question),我可以使用以下代码生成所需的输出(发布为答案只是为了完整性,因为@danlooo 答案也会产生相同的输出)。

library(XML)

r_list <- list(person1 = list(starts = letters[1:3], ends = letters[4:6]), person2 = list(starts = LETTERS[1:4], ends = LETTERS[5:8]))
str(r_list)

category = newXMLNode("category", attrs = c(name="personList"))

for(person in names(r_list))
  pers <- newXMLNode("pers", attrs = c(name = person), parent = category)
  startsn <- newXMLNode("starts", parent = pers)
  for(value in seq_along(r_list[[person]][["starts"]]))
    svalue <- newXMLNode("value", r_list[[person]][["starts"]][[value]], parent = startsn)
  
  endsn <- newXMLNode("ends", parent = pers)
  for(value in seq_along(r_list[[person]][["ends"]]))
    evalue <- newXMLNode("value", r_list[[person]][["ends"]][[value]], parent = endsn)
  

category

【讨论】:

以上是关于从 R 列表生成 xml的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP 从 HTML 列表生成 XML

非转义由 R XML 包生成的解析字符串?

从 XML 节点 java 生成/获取 xpath

从webservice wsdl生成代码

如何生成 R.java

修复styles.xml中的错误以生成R.java:找不到资源名称'Theme.AppCompat.Light'