R:如何基于xml文件中的嵌套结果来扩展data.frame


<StudyFieldsResponse>
<StudyFieldsList>
<StudyFields Rank="2">
<FieldValues Field="id">
<FieldValue>327635</FieldValue>
</FieldValues>
<FieldValues Field="Gender">
<FieldValue>Male</FieldValue>
<FieldValue>Female</FieldValue>
</FieldValues>
<FieldValues Field="code">
<FieldValue>55905</FieldValue>
</FieldValues>
</StudyFields>
<StudyFields Rank="3">
<FieldValues Field="id">
<FieldValue>555828</FieldValue>
</FieldValues>
<FieldValues Field="Gender">
<FieldValue>Male</FieldValue>
</FieldValues>
<FieldValues Field="code">
<FieldValue>55407-1139</FieldValue>
<FieldValue>77030</FieldValue>
<FieldValue>90901</FieldValue>
<FieldValue>23144</FieldValue>
</FieldValues>
</StudyFields>
</StudyFieldsList>
</StudyFieldsResponse>

我有上面的.xml文件。为了提取idGendercode记录,我对其进行了如下解析。

library(XML)
dat <- xmlParse(file = "example.xml")
final_dat <- xmlToDataFrame(nodes = xmlChildren(xmlRoot(dat)[["StudyFieldsList"]]))
names(final_dat) <- c("id", "Gender", "code")
> final_dat
id     Gender                      code
1 327635 MaleFemale                     55905
2 555828       Male 55407-1139770309090123144

但是,请注意,对于第一行,有2个Gender,雄性和雌性。类似地,对于第二个,有1个以上的codes。我如何扩展我的data.frame,使data.frame为每个唯一的idGendercode组合包含一个唯一的行?

> final_dat_expanded
id     Gender            code
1 327635       Male           55905
2 327635     Female           55905
3 555828       Male      55407-1139
4 555828       Male           77030
5 555828       Male           90901
6 555828       Male           23144

对于复杂的嵌套XML,请考虑XSLT,这是一种专门用于转换XML文件的语言。在Unix(Mac/Linux(上,R可以通过system调用开源实用程序xsltproc来运行XSLT1.0脚本。在Windows上,R可以运行参数化的PowerShell脚本。

具体来说,下面的XSLT针对代码下的最低级别FieldValue,然后有条件地检索id和gender的祖先节点,并使用for-each映射到gender的所有节点。

XSLT (另存为.xsl,一个特殊的.xml文件(

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/StudyFieldsResponse">
<xsl:copy>
<xsl:apply-templates select="descendant::FieldValues[@Field='code']/FieldValue"/>
</xsl:copy>
</xsl:template>

<xsl:template match="FieldValues[@Field='code']/FieldValue">
<xsl:variable name="curr_code"><xsl:value-of select="text()"/></xsl:variable>
<xsl:for-each select="ancestor::StudyFields/FieldValues[@Field='Gender']/FieldValue">
<xsl:copy>
<id><xsl:value-of select="ancestor::StudyFields/FieldValues[@Field='id']/FieldValue"/></id>
<gender><xsl:copy-of select="text()"/></gender>
<code><xsl:copy-of select="$curr_code"/></code>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

在线演示

R

library(XML)
# TRANSFORM INPUT TO FLATTER OUTPUT AND SAVE TO DISK
system("xsltproc style.xsl input.xml -o output.xml")
doc <- xmlParse("output.xml")
# BIND TO DATA FRAME
field_values_df <- xmlToDataFrame(doc)
field_values_df
#       id gender       code
# 1 327635   Male      55905
# 2 327635 Female      55905
# 3 555828   Male 55407-1139
# 4 555828   Male      77030
# 5 555828   Male      90901
# 6 555828   Male      23144

如果您使用Windows,请考虑PowerShell脚本

PowerShell(另存为.ps1(

param ($xml, $xsl, $output)
$xslt = New-Object System.Xml.Xsl.XslCompiledTransform
$xslt.Load($xsl)
$xslt.Transform($xml, $output)

R

library(XML)
# TRANSFORM INPUT TO FLATTER OUTPUT AND SAVE TO DISK
system("PowerShell -ExecutionPolicy bypass -File transform.ps1 input.xml style.xsl output.xml")
doc <- xmlParse("output.xml")
# BIND TO DATA FRAME
field_values_df <- xmlToDataFrame(doc)

最新更新