R中的XML到JSON转换

时间:2018-05-17 05:12:48

标签: r json xml

我尝试使用'XML'包library(rjson)。首先,我使用XML::xmlToList()解析XML并将其转换为列表,然后使用rjson包中的toJSON()将其转换为JSON。

我的XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

我的源代码:

rm(list = ls())
library(XML)
library(rjson)

xml_parse<-xmlParse(file = "path/book")
xml_root <- xmlRoot(xml_parse)
xml_list <- xmlToList(xml_root,addAttributes = T, simplify = F)
#rjson package
xml_rjson <-toJSON(xml_list)
cat(xml_rjson)

从rjson转换JSON文件:

  {
  "book": {
    "title": {
      "text": "Everyday Italian",
      ".attrs": {
        "lang": "en"
      }
    },
    "author": "Giada De Laurentiis",
    "year": "2005",
    "price": "30.00",
    ".attrs": {
      "category": "cooking"
    }
  },
  "book": {
    "title": {
      "text": "Harry Potter",
      ".attrs": {
        "lang": "en"
      }
    },
    "author": "J K. Rowling",
    "year": "2005",
    "price": "29.99",
    ".attrs": {
      "category": "children"
    }
  },
  "book": {
    "title": {
      "text": "Learning XML",
      ".attrs": {
        "lang": "en"
      }
    },
    "author": "Erik T. Ray",
    "year": "2003",
    "price": "39.95",
    ".attrs": {
      "category": "web"
    }
  }
}

由于重复的“book”重复而没有根名称“bookstore”,这显然是错误的。

理想的JSON文件是这样的:

{
  "bookstore": {
    "book": [
      {
        "-category": "cooking",
        "title": {
          "-lang": "en",
          "#text": "Everyday Italian"
        },
        "author": "Giada De Laurentiis",
        "year": "2005",
        "price": "30.00"
      },
      {
        "-category": "children",
        "title": {
          "-lang": "en",
          "#text": "Harry Potter"
        },
        "author": "J K. Rowling",
        "year": "2005",
        "price": "29.99"
      },
      {
        "-category": "web",
        "title": {
          "-lang": "en",
          "#text": "Learning XML"
        },
        "author": "Erik T. Ray",
        "year": "2003",
        "price": "39.95"
      }
    ]
  }
}

期待解决方案。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

正如迈克尔所说,这不是一个好主意。但是,我们不太可能说服你,因为没有自动转换意味着要做的工作是为了确保一致性和完全可重复性。

由于您似乎喜欢该网站,我非常确定它使用xml-js或非常接近它的东西,所以我把一个小的V8包装器放在一起包裹:https://github.com/hrbrmstr/blackmagic

xml_to_json()函数的潜在参数设置有,所以在任何&#34之前查看它;但它没有&# 39; t为我自动做xyz&#34; 评论。

devtools::install_github("hrbrmstr/blackmagic")

'<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>' -> books

cat(xml_to_json(books, spaces = 2, compact = TRUE, ignoreDeclaration = TRUE))

## {
##   "bookstore": {
##     "book": [
##       {
##         "_attributes": {
##           "category": "cooking"
##         },
##         "title": {
##           "_attributes": {
##             "lang": "en"
##           },
##           "_text": "Everyday Italian"
##         },
##         "author": {
##           "_text": "Giada De Laurentiis"
##         },
##         "year": {
##           "_text": "2005"
##         },
##         "price": {
##           "_text": "30.00"
##         }
##       },
##       {
##         "_attributes": {
##           "category": "children"
##         },
##         "title": {
##           "_attributes": {
##             "lang": "en"
##           },
##           "_text": "Harry Potter"
##         },
##         "author": {
##           "_text": "J K. Rowling"
##         },
##         "year": {
##           "_text": "2005"
##         },
##         "price": {
##           "_text": "29.99"
##         }
##       },
##       {
##         "_attributes": {
##           "category": "web"
##         },
##         "title": {
##           "_attributes": {
##             "lang": "en"
##           },
##           "_text": "Learning XML"
##         },
##         "author": {
##           "_text": "Erik T. Ray"
##         },
##         "year": {
##           "_text": "2003"
##         },
##         "price": {
##           "_text": "39.95"
##         }
##       }
##     ]
##   }
## }

答案 1 :(得分:0)

第一点:没有单一的确定“正确”方法将XML转换为JSON,反之亦然。有许多不同的库可以做到这一点,而且它们都采用不同的方式。不幸的是选择一个实际生成错误JSON的文件。

第二点:如果你知道你开始使用什么XML并且知道你想要最终使用什么JSON,那么你找到一个能够完成所需转换的库是不太可能的。

因此,您将不得不进行一些手动调整。您可以在转换之前预先处理输入,或者在转换后对输出进行后处理,或者您可以“手动”完成整个操作。

在XSLT中(或者可能在R中,但是我不熟悉它),手工完成整个事情实际上并不困难。)

我个人的选择是使用XSLT 3.0将XML转换为地图和数组,然后将结果序列化为JSON:

<xsl:output method="json" indent="yes">

<xsl:template match="booklist">
  <xsl:map-entry key="'booklist'">
    <xsl:map-entry key="'book'">
      <saxon:array>
        <xsl:for-each select="book">
          <saxon:array-member>
          <xsl:map>
           <xsl:map-entry key="'-category'" select="@category"/>
           <xsl:map-entry key="'title'">
             <xsl:apply-templates select="title"/>
           </xsl:map-entry>
           <xsl:map-entry key="'author'" select="author"/>
           <xsl:map-entry key="'year'" select="year"/>
           <xsl:map-entry key="'price'" select="price"/>
         </xsl:map>
         </saxon:array-member>
       </xsl:for-each>
     </saxon:array>
   </xsl:map-entry>
 </xsl:map-entry>
</xsl:template>

<xsl:template match="title">
  <xsl:map-entry key="'-lang'" select="@lang"/>
  <xsl:map-entry key="'#text'" select="string(.)"/>
</xsl:template>

当然,您也可以尝试概括其中一些规则,例如:拥有一个匹配所有属性的模板规则。