使用 R 和 xml2 库提取嵌套 XML 数据
Extracting Nested XML data using R and xml2 library
我有以下嵌套 XML 文件的信息,我正试图将其转换为 data.frame 以供分析和报告:
<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=11=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
我能够读取 XML 文件并提取一小部分,如下所示:
file <- '<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=12=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
'
data <- read_xml(file)
xml_find_all(data,"//node/node[@TEXT = 'Scale']/node/@TEXT")
但我真正需要做的是以 data.frame 的形式获取它,如下所示:
Node1 Node2 Node3
"Cost" "Scale" "1 - [=13=] to 0"
"Cost" "Scale" "2 - 0 to 0"
"Cost" "Scale" "3 - 0 to 00"
"Cost" "Scale" "4 - 00 to 00"
"Cost" "Scale" "5 - 00 +"
"Cost" "Weight" "1"
有人能指出我正确的方向吗?
为了重塑 XML,我喜欢使用 XSLT,这是一种通用的 XML 转换语言。 R 包 xslt
允许您使用 R 中的 XSLT 转换 XML 文件。
在这种情况下,您可以将其转换为 HTML table,您可以使用 rvest
:
轻松解析它
library(tidyverse)
library(xslt)
library(rvest)
file <- '<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=10=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
'
data <- read_xml(file)
xslt <- '<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html><table><xsl:apply-templates select="node/node/node"/></table></html>
</xsl:template>
<xsl:template match="node">
<tr>
<td><xsl:value-of select="../../@TEXT"/></td>
<td><xsl:value-of select="../@TEXT"/></td>
<td><xsl:value-of select="@TEXT"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>'
style <- read_xml(xslt)
xml_xslt(data, style) %>%
rvest::html_table() %>%
.[[1]]
#> X1 X2 X3
#> 1 Cost Scale 1 - [=10=] to 0
#> 2 Cost Scale 2 - 0 to 0
#> 3 Cost Scale 3 - 0 to 00
#> 4 Cost Scale 4 - 00 to 00
#> 5 Cost Scale 6 - 00 +
#> 6 Cost Weight 1
除了使用 xslt
,您还可以只遍历节点列表。这里我们选择所有的三层深度的节点,然后从所有的父节点中提取TEXT属性(最后用dplyr
绑定在一起)
library(dplyr)
xml_find_all(doc,"//node/node/node") %>% lapply(function(x) {
list(
NODE1=x %>% xml_parent %>% xml_parent %>% xml_attr("TEXT"),
NODE2=x %>% xml_parent %>% xml_attr("TEXT"),
NODE3=x %>% xml_attr("TEXT")
)
}) %>% bind_rows()
我有以下嵌套 XML 文件的信息,我正试图将其转换为 data.frame 以供分析和报告:
<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=11=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
我能够读取 XML 文件并提取一小部分,如下所示:
file <- '<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=12=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
'
data <- read_xml(file)
xml_find_all(data,"//node/node[@TEXT = 'Scale']/node/@TEXT")
但我真正需要做的是以 data.frame 的形式获取它,如下所示:
Node1 Node2 Node3
"Cost" "Scale" "1 - [=13=] to 0"
"Cost" "Scale" "2 - 0 to 0"
"Cost" "Scale" "3 - 0 to 00"
"Cost" "Scale" "4 - 00 to 00"
"Cost" "Scale" "5 - 00 +"
"Cost" "Weight" "1"
有人能指出我正确的方向吗?
为了重塑 XML,我喜欢使用 XSLT,这是一种通用的 XML 转换语言。 R 包 xslt
允许您使用 R 中的 XSLT 转换 XML 文件。
在这种情况下,您可以将其转换为 HTML table,您可以使用 rvest
:
library(tidyverse)
library(xslt)
library(rvest)
file <- '<node TEXT="Cost">
<node TEXT="Scale">
<node TEXT="1 - [=10=] to 0">
</node>
<node TEXT="2 - 0 to 0">
</node>
<node TEXT="3 - 0 to 00">
</node>
<node TEXT="4 - 00 to 00">
</node>
<node TEXT="6 - 00 +">
</node>
</node>
<node TEXT="Weight">
<node TEXT="1">
</node>
</node>
</node>
'
data <- read_xml(file)
xslt <- '<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html><table><xsl:apply-templates select="node/node/node"/></table></html>
</xsl:template>
<xsl:template match="node">
<tr>
<td><xsl:value-of select="../../@TEXT"/></td>
<td><xsl:value-of select="../@TEXT"/></td>
<td><xsl:value-of select="@TEXT"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>'
style <- read_xml(xslt)
xml_xslt(data, style) %>%
rvest::html_table() %>%
.[[1]]
#> X1 X2 X3
#> 1 Cost Scale 1 - [=10=] to 0
#> 2 Cost Scale 2 - 0 to 0
#> 3 Cost Scale 3 - 0 to 00
#> 4 Cost Scale 4 - 00 to 00
#> 5 Cost Scale 6 - 00 +
#> 6 Cost Weight 1
除了使用 xslt
,您还可以只遍历节点列表。这里我们选择所有的三层深度的节点,然后从所有的父节点中提取TEXT属性(最后用dplyr
绑定在一起)
library(dplyr)
xml_find_all(doc,"//node/node/node") %>% lapply(function(x) {
list(
NODE1=x %>% xml_parent %>% xml_parent %>% xml_attr("TEXT"),
NODE2=x %>% xml_parent %>% xml_attr("TEXT"),
NODE3=x %>% xml_attr("TEXT")
)
}) %>% bind_rows()