[英]R: How to expand a data.frame based on nested results in xml file
<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
文件。 為了提取id
、 Gender
和code
記錄,我對其進行了如下解析。
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
,男性和女性。 同理,對於第二個, code
也不止1個。 如何擴展我的 data.frame 以便 data.frame 包含每個唯一id
、 Gender
和code
組合的唯一行?
> 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 可以通過對開源實用程序xsltproc
進行system
調用來運行 XSLT 1.0 腳本。 在 Windows、R 上可以運行參數化的 PowerShell 腳本。
具體來說,在 XSLT 下面針對 code 下的最低級別 FieldValue ,然后有條件地檢索祖先節點的 id 和 gender ,並使用for-each
映射所有性別節點。
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.