如何解决XML和XSLT-V2处理或R中的嵌套嵌套列表-药品福利计划中的数据 解决方案的一部分
问题:
很长时间以来,我和我的大学一直在尝试将药品福利计划V3 XML(https://www.pbs.gov.au/browse/downloads)转换为可用格式,但是我们取得的成功有限。我已经能够将PBS XML V3转换为列表的R列表,但是以编程方式将其解压缩为可用格式非常困难。
PBS_V3_XML_Doc <- read_xml(x = Path_to_PBS_V3_XML_File,options = c("RECOVER","NOBLANKS","HUGE") # Important options that enable import.
# Lifts hardcoded limitations because of the massive file size,verbose = TRUE) # Enables message print Feedback
PBS_V3_XML_NameSpaces <- xml_ns(PBS_V3_XML_Doc) # xml namespaces
PBS_V3_XML_List <- xml2::as_list(x = PBS_V3_XML_Doc) # converts the XML document into a R list object
我尝试过组合unnest_wider,unnest_longer,unnest,unlist,unnest_auto以及更多(下面有一些)。但是我们还没有运气。
Test_docall_unnest <- do.call(c,unlist(PBS_V3_XML_List,recursive=FALSE))
flattenlist <- function(x){
morelists <- sapply(x,function(xprime) class(xprime)[1]=="list")
out <- c(x[!morelists],unlist(x[morelists],recursive=FALSE))
if(sum(morelists)){
Recall(out)
}else{
return(out) }}
recursive_unnest <- function(.data) {
# Exit condition: no more 'children' list-column
if (!"children" %in% names(.data) || !is.list(.data[["children"]])) return(.data)
x <- unnest(.data)
# Minor clean-up to make unnest work: replace NULLs with empty data frames
x <- mutate_if(x,is.list,~ map_if(.x,~ is.null(.x) || identical(.x,list()),~ data.frame(date = NA))) Recall(x)
}
解决方案的一部分
使用样式表可能有效,但是xslt软件包不接受版本2或更高版本的XML样式表,因此可悲的是,该软件包无法解决这种情况。 我试过使用PBS V3 Schema found here中的一些xsl样式表,但是老实说我不确定应该使用哪个样式表(我已经尝试过/ xsl文件夹中的文件)
解决方法
为什么R的xslt
软件包不能运行XSLT 1.0脚本? XSLT 1.0脚本可以展平所需的节点,并将其所有后代限制为具有文本信息的节点。重复的节点似乎是<previous>
标签。扁平化后,转换后的XML可以轻松迁移到数据帧中。每个后代都有其父名称和祖父母名称附加到返回名称,以完成数据框列。
XSLT (另存为.xsl,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pbs="http://schema.pbs.gov.au/"
xmlns:p="http://pbs.gov.au/"
xmlns:dbk="http://docbook.org/ns/docbook"
xmlns:db="http://docbook.org/ns/docbook#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dct="http://purl.org/dc/terms/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:ext="http://extension.schema.pbs.gov.au/"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="pbs:root">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="pbs:previous-list"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pbs:previous-list">
<xsl:apply-templates select="pbs:previous"/>
</xsl:template>
<xsl:template match="pbs:previous">
<data>
<xsl:for-each select="descendant::*">
<xsl:if test="text() != ''">
<xsl:element name="{translate(concat(local-name(../parent::*),'_',local-name(parent::*),local-name()),'-','_')}">
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
R
library(xml2)
library(xslt)
library(dplyr)
# INPUT SOURCE
doc <- read_xml("/path/to/sch-2020-09-01-r1.xml")
style <- read_xml("/path/to/style.xsl",package = "xslt")
# TRANSFORM
new_xml <- xml_xslt(doc,style)
# RETRIEVE data NODES
recs <- xml_find_all(new_xml,"//data")
# BIND EACH CHILD TEXT AND NAME TO Player DFs
df_list <- lapply(recs,function(r)
data.frame(rbind(setNames(xml_text(xml_children(r)),xml_name(xml_children(r)))),stringsAsFactors = FALSE)
)
# BIND ALL DFs TO SINGLE MASTER DF
final_df <- dplyr::bind_rows(df_list)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。