【问题标题】:generate function calls to modify xml with R生成函数调用以使用 R 修改 xml
【发布时间】:2019-02-12 18:29:45
【问题描述】:

我想使用 R 和 xml2 动态修改 XML 文档:我的方法是将参数准备好到数据框中,然后将这些参数传递给将修改 xml 文档的函数。

library(xml2)

doc <- xml2::read_xml('<CATALOG>
<PLANT myid="1">
  <COMMON>Bloodroot</COMMON>
  <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
  <ZONE>4</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$2.44</PRICE>
  <AVAILABILITY>031599</AVAILABILITY>
  </PLANT>
  <PLANT myid="2">
  <COMMON>Columbine</COMMON>
  <BOTANICAL>Aquilegia canadensis</BOTANICAL>
  <ZONE>3</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$9.37</PRICE>
  <AVAILABILITY>030699</AVAILABILITY>
  </PLANT>
  <PLANT myid="3">
  <COMMON>Marsh Marigold</COMMON>
  <BOTANICAL>Caltha palustris</BOTANICAL>
  <ZONE>4</ZONE>
  <LIGHT>Mostly Sunny</LIGHT>
  <PRICE>$6.81</PRICE>
  <AVAILABILITY>051799</AVAILABILITY>
  </PLANT>
  <PLANT myid="4">
  <COMMON>Cowslip</COMMON>
  <BOTANICAL>Caltha palustris</BOTANICAL>
  <ZONE>4</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$9.90</PRICE>
  <AVAILABILITY>030699</AVAILABILITY>
  </PLANT>
  <PLANT myid="5">
  <COMMON>Dutchman\'s-Breeches</COMMON>
  <BOTANICAL>Dicentra cucullaria</BOTANICAL>
  <ZONE>3</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$6.44</PRICE>
  <AVAILABILITY>012099</AVAILABILITY>
  </PLANT>
  <PLANT myid="6">
  <COMMON>Ginger, Wild</COMMON>
  <BOTANICAL>Asarum canadense</BOTANICAL>
  <ZONE>3</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$9.03</PRICE>
  <AVAILABILITY>041899</AVAILABILITY>
  </PLANT>
  <PLANT myid="7">
  <COMMON>Hepatica</COMMON>
  <BOTANICAL>Hepatica americana</BOTANICAL>
  <ZONE>4</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$4.45</PRICE>
  <AVAILABILITY>012699</AVAILABILITY>
  </PLANT>
  </CATALOG>'

)


xpath <-  "//PLANT[@myid='2']"
xml_find_all(doc,xpath)

newxml <- function(xmldoc, xpath, newattr) {

  #
  VarName <- xml2::xml_find_all(xmldoc, xpath)
  xml_attr(VarName, "Name") <- newattr

}

现在,如果我想根据 id 修改这个由数千种植物组成的 XML 文档(我可以将 xpath 和新值存储在数据框或向量中),我应该如何进行?

我尝试了以下方法:

do.call(newxml,list(xmldoc = doc, xpath= dftest$xpath, 
                       newattr = dftest$newname))

但它不起作用,它告诉我:

 Error in xpath_search(x$node, x$doc, xpath = xpath, nsMap = ns, num_results = Inf) : 
  Expecting a single string value: [type=character; extent=5]. 

显然,我想念 R 的一些重要内容,但我不知道是什么,也请随时提出解决此问题的更好方法。

【问题讨论】:

    标签: r xml2


    【解决方案1】:

    看起来问题在于将您的数据框列作为函数参数传递。

    如果我传入单数参数,该函数似乎会提供结果:

    xpath <-  "//PLANT[@myid='2']"
    xml_find_all(doc,xpath)
    newxml <- function(xmldoc, xpath, newattr) {
    
      #
      VarName <- xml2::xml_find_all(xmldoc, xpath)
      xml_attr(VarName, "Name") <- newattr
    
    }
    do.call(newxml,list(xmldoc = doc, xpath= xpath, 
                        newattr = "TESTING"))
    

    产生如下:

     xml_find_all(doc,xpath)
    {xml_nodeset (1)}
    [1] <PLANT myid="2" Name="TESTING">\n  <COMMON>Columbine</COMMON>\n
    

    我认为数据框中的数据类型也可能是因素而不是字符串

    我使用了以下:

    newxml <- function(xpath, newattr,xmldoc=doc) {
      VarName <- xml2::xml_find_all(xmldoc, as.character(xpath))
      xml_attr(VarName, "Name") <- as.character(newattr)
    }
    
    df <- data.frame(a= c(xpath,xpath),b = c("TEST1","TEST2"))
    mapply(newxml,df$a, df$b)
    

    use multiple columns as variables with sapply

    【讨论】:

    • 感谢RK1的回复,你说得对,主要是dtype错误,而我更关注do.call部分。您使用数据框的 mapply 方法也很有趣。
    • 太棒了 --- 是的,我只使用了 mapply,因为它让我想起了 python 中的 apply 和 lambda
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 2020-01-22
    • 2020-09-21
    相关资源
    最近更新 更多