Создать фрейм данных из xml с разным количеством элементов - PullRequest
3 голосов
/ 10 марта 2020

Я довольно новичок в R, пытаюсь получить некоторые данные из xml -документа во фрейм данных. Он работает нормально, когда каждый узел имеет одинаковое количество дочерних элементов, но у меня возникают проблемы, когда его нет.

Код R, который я использую, выглядит следующим образом:

library(XML)

xml.m_data <- xmlParse(file="mdata.xml")

df.m_data <- xmlToDataFrame(xml.m_data,nodes = getNodeSet(xml.m_data,"//Row"),collectNames=T)

nodeset <- getNodeSet(xml.m_data,"//Row")[[1]]
    colnames <- c()
    i <- NULL
    for(i in 1:(length(df.m_data))){
        x <- toString.XMLNode(nodeset[i])
        x <- strsplit(x,"\"")[[1]][2]
        colnames[i] <- x
        }
    colnames(df.m_data) <- colnames
    rm(colnames)

Результат, который я пытаюсь получить, выглядит примерно так (результат второго XML):

 CompanyID ProdConsID      UnitID  UnitName Commodity Facility     Source Commercialisation           StartDate
1 COMPANY001    E000001 E000001-001  Name_001     Power Producer Fossil Gas             False 2010-01-31T23:00:00
2 COMPANY002    E000002 E000002-001  Name_002     Power Producer Fossil Gas             False 2010-01-31T23:00:00
3 COMPANY003    E000003 E000003-001 Name_003A     Power Producer Fossil Gas              True 2009-10-25T23:00:00
4 COMPANY003    E000003 E000003-002 Name_003B     Power Producer Fossil Gas              True 2009-10-25T23:00:00

Есть два xmls, первый из которых я могу обработать, второй нет.

Для второго я получаю следующую ошибку:

Error in `[<-.data.frame`(`*tmp*`, i, names(nodes[[i]]), value = c("COMPANY001",  : duplicate subscripts for columns

Пример 1:

<Results>
    <Result>
        <Row>
            <Field Name="CompanyID">COMPANY001</Field>
            <Field Name="ProdConsID">E000001</Field>
            <Field Name="UnitID">E000001-001</Field>
            <Field Name="UnitName">Name_001</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">False</Field>
            <Field Name="StartDate">2010-01-31T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY002</Field>
            <Field Name="ProdConsID">E000002</Field>
            <Field Name="UnitID">E000002-001</Field>
            <Field Name="UnitName">Name_002</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">False</Field>
            <Field Name="StartDate">2010-01-31T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY003</Field>
            <Field Name="ProdConsID">E000003</Field>
            <Field Name="UnitID">E000003-001</Field>
            <Field Name="UnitName">Name_003A</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">True</Field>
            <Field Name="StartDate">2009-10-25T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY003</Field>
            <Field Name="ProdConsID">E000003</Field>
            <Field Name="UnitID">E000003-002</Field>
            <Field Name="UnitName">Name_003B</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">True</Field>
            <Field Name="StartDate">2009-10-25T23:00:00</Field>
        </Row>  
    </Result>
</Results>

Пример 2:

<Results>
    <Result>
        <Row>
            <Field Name="CompanyID">COMPANY001</Field>
            <Field Name="ProdConsID">E000001</Field>
            <Field Name="UnitID">E000001-001</Field>
            <Field Name="UnitName">Name_001</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">False</Field>
            <Field Name="StartDate">2010-01-31T23:00:00</Field>
            <Field Name="EndDate">2015-12-09T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY002</Field>
            <Field Name="ProdConsID">E000002</Field>
            <Field Name="UnitID">E000002-001</Field>
            <Field Name="UnitName">Name_002</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">False</Field>
            <Field Name="StartDate">2010-01-31T23:00:00</Field>
            <Field Name="EndDate">2015-12-09T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY003</Field>
            <Field Name="ProdConsID">E000003</Field>
            <Field Name="UnitID">E000003-001</Field>
            <Field Name="UnitName">Name_003A</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">True</Field>
            <Field Name="StartDate">2009-10-25T23:00:00</Field>
        </Row>
        <Row>
            <Field Name="CompanyID">COMPANY003</Field>
            <Field Name="ProdConsID">E000003</Field>
            <Field Name="UnitID">E000003-002</Field>
            <Field Name="UnitName">Name_003B</Field>
            <Field Name="Commodity">Power</Field>
            <Field Name="Facility">Producer</Field>
            <Field Name="Source">Fossil Gas</Field>
            <Field Name="Commercialisation">True</Field>
            <Field Name="StartDate">2009-10-25T23:00:00</Field>
        </Row>  
    </Result>
</Results>

Любая полезная информация приветствуется.

Ответы [ 2 ]

2 голосов
/ 10 марта 2020

Я предпочитаю пакет xml2 вместо XML из-за более простого синтаксиса. Решение здесь читает все родительские узлы «строки», а затем анализирует каждый из них, чтобы получить серию из 1 строк данных, а затем объединяет все результаты в окончательный ответ.
Функция bind_rows() из dplyr Пакет может обрабатывать пропущенные столбцы.
Подробнее см. комментарии к коду.

library(xml2)
library(dplyr)

#list of files to process
fnames<-"results2.xml"

doc<-read_xml(fnames)

#find parent nodes
parents<-xml_find_all(doc, ".//Row")

dfs<-lapply(parents, function(parent) {

  #find all of the nodes/records under each parent node
  titles <- xml_children(parent) %>% html_attr("Name")
  values <- xml_children(parent) %>% html_text()

  #make data frame of the values and column headings
  df<-as.data.frame(t(values), stringsAsFactors = FALSE)
  names(df)<-titles
  df
})

#Make combinded dataframe
answer<-bind_rows(dfs)
answer



   CompanyID ProdConsID      UnitID  UnitName Commodity Facility     Source Commercialisation           StartDate             EndDate
1 COMPANY001    E000001 E000001-001  Name_001     Power Producer Fossil Gas             False 2010-01-31T23:00:00 2015-12-09T23:00:00
2 COMPANY002    E000002 E000002-001  Name_002     Power Producer Fossil Gas             False 2010-01-31T23:00:00 2015-12-09T23:00:00
3 COMPANY003    E000003 E000003-001 Name_003A     Power Producer Fossil Gas              True 2009-10-25T23:00:00                <NA>
4 COMPANY003    E000003 E000003-002 Name_003B     Power Producer Fossil Gas              True 2009-10-25T23:00:00                <NA>
1 голос
/ 10 марта 2020

Рассмотрим внутренний XML метод xmlAttrsToDataframe(), использующий оператор тройного двоеточия для извлечения атрибутов в поля имен с помощью setNames:

df <- setNames(XML::xmlToDataFrame(xml.m_data, nodes=getNodeSet(xml.m_data, path="//Row")),
               unique(XML:::xmlAttrsToDataFrame(getNodeSet(xml.m_data, path='//Field')))$Name)

df

#    CompanyID ProdConsID      UnitID  UnitName Commodity Facility     Source Commercialisation           StartDate
# 1 COMPANY001    E000001 E000001-001  Name_001     Power Producer Fossil Gas             False 2010-01-31T23:00:00
# 2 COMPANY002    E000002 E000002-001  Name_002     Power Producer Fossil Gas             False 2010-01-31T23:00:00
# 3 COMPANY003    E000003 E000003-001 Name_003A     Power Producer Fossil Gas              True 2009-10-25T23:00:00
# 4 COMPANY003    E000003 E000003-002 Name_003B     Power Producer Fossil Gas              True 2009-10-25T23:00:0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...