От новичка до гуру: Курсы программирования на CyberDuff

Прочитайте XML-файл в R и создайте фрейм данных, когда узлы имеют разную длину и содержимое.

Я пытаюсь создать объект dataframe из файла XML. Задача казалась простой, но после многих попыток я не могу извлечь именно то, что хочу.

Исходные данные взяты отсюда:
https://www.data.gouv.fr/fr/datasets/repertoire-national-des-certifications-professionnelles-et-repertoire-specifique/#resource-071a7029-f237-40b1-81ca-e3c1d78282b7

По сути, документ имеет более 17 тысяч узлов с тем же именем, что и FICHES. Одним из таких подузлов является BLOCS_COMPETENCES. У этого подузла есть еще один под названием BLOC_COMPETENCES (разница в том, что S в BLOC), и у этого есть 2 интересующих меня узла: CODE и LIBELLE.

Однако не все FICHES имеют одинаковые атрибуты и/или дочерние узлы. Более того, некоторые из них имеют 1 BLOC_COMPETENCES с 1, 2, 3 или вообще без элементов.

Следуя этому документу (среди прочих сообщений), я попытался извлечь корневой узел и получить доступ к элементам с помощью xpath:

# Import the file after zip extraction
RNCP_aout2020 <- xmlParse("U:/RNCP_2020/Fiches-rncp-2020-08-03/export_fiches_RNCP_2020-08-03.xml", encoding = "UTF-8")

# Finding root node
rootNode <- xmlRoot(RNCP_aout2020)

BLOCS_COMPETENCES <- as.data.frame(xpathSApply(rootNode, '/FICHES/FICHE/BLOCS_COMPETENCES/BLOC_COMPETENCES/CODE', xmlValue))

Это работает для извлечения всех присутствующих узлов и атрибутов. Например, следующая строка работает при извлечении идентификатора каждой FICHES:

# Extract ID
NUMERO_FICHE <- as.data.frame(xpathSApply(rootNode, '/FICHES/FICHE/NUMERO_FICHE', xmlValue))

Но когда я пытаюсь использовать это для BLOC_COMPETENCES, длина отличается, что делает невозможным слияние с другими столбцами.

Я могу предоставить весь код, который я пробовал, но не репрекс в формате CSS (на данный момент), потому что я не знаю, как подмножить большой файл.

Любая помощь будет действительно оценена!


Ответы:


1

Переменное число BLOC_COMPETENCES действительно усложняет проблему. В приведенном ниже сценарии проанализированы все узлы микрофиши, а затем пройдены по каждому узлу, чтобы получить нужные коды и клеветы. Также необходимо проверить наличие кодов нулевой длины и клеветы. Так как список фиш очень длинный, для выполнения оператора lapply потребуется некоторое время.

library(xml2)
library(dplyr)

#read the document
page <- read_xml("export_fiches_RNCP_2020-08-03.xml")

#read all fiches nodes
fiches <- xml_find_all(page, "//FICHE")

#parse each fiches
dfs <-lapply(fiches, function(node){
   id <- node %>% xml_find_first(".//ID_FICHE")  %>% xml_text()
   codes <-  node %>% xml_find_all(".//BLOC_COMPETENCES/CODE") %>% xml_text()
   libelles <- node %>% xml_find_all(".//BLOC_COMPETENCES/LIBELLE")%>% xml_text()
   #correct for codes which don't exist
   if (length(codes) <1 ) {codes = NA}
   if (length(libelles) <1 ) {libelles = NA}

   df<- data.frame(id, codes, libelles, stringsAsFactors = FALSE)
})

#merge all of the data frames
answer <- bind_rows(dfs)
07.09.2020
  • Большое спасибо за ваш ответ ! Если вы не возражаете, могу я спросить, сколько времени это заняло на вашей машине? Я пробовал даже с параллельным кодом (mclapply), но задача просто не выполняется (ожидание более 30 минут). 08.09.2020
  • Некоторые новости здесь. Оставил на это около часа и выполнил задание. Работает идеально! Я отмечаю это как окончательный ответ, потому что он больше адаптируется к моему опыту работы с R, чем другой. 08.09.2020
  • Я боялся, что ты задашь этот вопрос. На моем Core i5 с частотой 3,2 ГГц это заняло около 20 минут. Я не думаю, что каждая итерация в циклах занимает так много времени, это просто большое количество итераций, поэтому параллельный запуск может не сэкономить время. 09.09.2020

  • 2

    Используйте XSLT для преобразования исходного XML для извлечения необходимых узлов. Затем используйте удобный обработчик xmlToDataFrame, избегая for или apply семейных циклов или логики if.

    Поскольку XSLT 1.0 является независимым переносимым отраслевым языком, существует множество способов его запуска, включая процессоры, такие как xsltproc, через другие языки (Java, Python, PHP) или с пакетом R xslt.

    XSLT (сохранить как файл .xsl, специальный файл .xml, используемый ниже)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <!-- EXTRACT ONLY FICHE NODES -->
        <xsl:template match="/FICHES">
         <xsl:copy>
           <xsl:apply-templates select="FICHE"/>
         </xsl:copy>
        </xsl:template>
        
        <!-- WITHIN EACH FICHE NODE, EXTRACT ONLY ITS DESCENDANT, BLOC_COMPETENCES NODES-->
        <xsl:template match="FICHE">
           <xsl:apply-templates select="descendant::BLOC_COMPETENCES"/>
        </xsl:template>
        
        <!-- WITHIN EACH BLOC_COMPETENCE, DO TWO THINGS:            -->
        <!--      1. RETRIEVE UPPER LEVEL ANCESTOR NODE, ID_FICHE   -->
        <!--      2. RETRIEVE CODE AND LIBELLE CHILD NODES          -->
        <xsl:template match="BLOC_COMPETENCES">
         <xsl:copy>
           <xsl:copy-of select="ancestor::FICHE/ID_FICHE"/>
           <xsl:copy-of select="CODE | LIBELLE"/>
         </xsl:copy>
        </xsl:template>
        
    </xsl:stylesheet>
    

    Подход 1 (используя описанный выше XSLT в файле с именем style.xsl)

    R + xsltproc

    library(XML)
    
    setwd("...")
    system("xsltproc -o transformed.xml style.xsl export_fiches_RNCP_2020-08-03.xml")
    
    doc <- xmlParse("transformed.xml")
    doc
    # <FICHES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC01</CODE>
    #     <LIBELLE>Du dérushage au montage</LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC02</CODE>
    #     <LIBELLE>Analyser un projet cinématographique</LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC03</CODE>
    #     <LIBELLE>Tourner sur fond d'incrustation </LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #   ...
    
    df <- xmlToDataFrame(doc)
    

    Подход 2 (используя описанный выше XSLT в файле с именем style.xsl)

    R + xslt

    library(xml2)
    library(xslt)
    library(XML)
    
    # PARSE XML AND XSLT
    doc <- read_xml('export_fiches_RNCP_2020-08-03.xml')
    style <- read_xml('style.xsl', package = "xslt")
    
    # TRANSFORM NESTED INPUT INTO FLATTER OUTPUT
    new_xml <- as.character(xslt::xml_xslt(doc, style))
    
    # PARSE FLATTER XML
    flat_xml <- XML::xmlParse(new_xml, asText=TRUE)
    
    # BUILD DATA FRAME
    df <- xmlToDataFrame(doc)
    
    07.09.2020
  • Большое спасибо за этот полный ответ! Однако я должен признать, что я не очень хорошо знаком с тем, о чем вы говорите в первой части вашего ответа. Можете ли вы порекомендовать какой-нибудь учебник для начинающих (или, что еще лучше, сертифицированный онлайн-курс)? Мне также любопытно, как вы получили образец или предварительный просмотр в формате JSS. Я попробовал код, который вы написали, но получаю следующую ошибку: Ошибка в (функции (классы, fdef, mtable): невозможно найти унаследованный метод для функции «xmlToDataFrame» для подписи «xml_document, отсутствует, отсутствует, отсутствует, отсутствует». 08.09.2020
  • Я забыл добавить важную инструкцию: (сохранить как файл .xsl, специальный файл .xml). См. редактирование. Специальный курс не нужен. Возможно, вы слышали о SQL, внешнем декларативном языке специального назначения, который R может запускать для извлечения данных из реляционных баз данных. Что ж, XSLT также является внешним декларативным языком специального назначения, который R может запускать для преобразования (например, выравнивания) XML-файлов, используя специальный XML-файл для запуска своего кода. Я покажу два способа сделать это в R: с помощью внешнего процессора, доступного на машинах Unix (Mac/Linux), и с помощью пакета. Примечание: петля не нужна и не занимает часа! 08.09.2020
  • Я снова попробовал вашу альтернативу, потому что другое решение требует огромного количества времени, но я действительно не заставляю его работать. Спасибо в любом случае. Я надеюсь, что это поможет кому-то еще. 15.09.2020
  • Вам не удалось установить пакет xslt (родственный пакету xml2)? В чем ошибка? В вашем сообщении указано, что у вас есть XML, и принятый ответ у вас будет xml2. 15.09.2020
  • У меня работает пакет xslt. Я думаю, что это было связано с проблемой обновления. Во всяком случае, я слышал о SQL, я знаю, что такое реляционная база данных, и я понимаю, что мне не нужны циклы для доступа к информации. Чего я не понимаю, так это первой части вашего ответа (начинающейся с ‹xsl:stylesheet), которую я считаю самой важной частью. Что это все за параметры? Откуда ты знаешь, что туда положить? Откуда вы знаете, где писать ‹xsl:template match=/FICHES› вместо (например) ‹/xsl:copy›. Фрагмент, в котором вы создаете файл xsl, если хотите. В случае, если мне нужно сделать это с другими параметрами. 27.10.2020
  • Первый блок представляет собой отдельный код или файл сценария (например, .sql в SQL, .java в Java, .py в Python или даже скрипт .R в R). На самом деле это специальный файл XML, который отправляет инструкции механизму XSLT. Обучение рекурсивному шаблонному стилю XSLT выходит за рамки вопроса StackOverflow. Однако я добавляю комментарии в первый фрагмент, чтобы показать, что делает каждый шаблон. Немногим это не нравится или не понятно, но XSLT мне нравится! 27.10.2020
  • Ладно, теперь намного понятнее. Сначала я подумал, что это пакет или какой-то простой обходной путь, а потом понял, что это буквально другой язык. Что ж, я полностью согласен с вами в том смысле, что он выглядит потрясающе, полностью обрабатывая файлы xml. Однако, учитывая то короткое время, которое у меня было для управления проектом, я не особо стремился изучать другой язык. НО это идет прямо в мой список дел. Я уже пробовал некоторые настройки с данными, которые я обрабатываю, но должен прочитать документацию и полностью использовать ее. Большое спасибо за ваши ответы и ваше время! 28.10.2020
  • Новые материалы

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

    Я предполагаю, что вы имеете в виду методы обработки категориальных данных.
    Я предполагаю, что вы имеете в виду методы обработки категориальных данных. Пожалуйста, проверьте мой пост Инструментарий специалиста по данным для кодирования категориальных переменных в..

    Игра в прятки с данными
    Игра в прятки с данными Я хотел бы, чтобы вы сделали мне одолжение и ответили на следующие вопросы. Гуглить можно в любое время, здесь никто не забивается. Сколько регионов в Гане? А как..

    «Раскрытие математических рассуждений с помощью Microsoft MathPrompter и моделей больших языков»
    TL;DR: MathPrompter от Microsoft показывает, как использовать математические рассуждения с большими языковыми моделями; 4-этапный процесс для улучшения доверия и рассуждений в математических..

    Раскройте свой потенциал в области разработки мобильных приложений: Абсолютная бесплатная серия
    Глава 6: Работа в сети и выборка данных Глава 1: Введение в React Native Глава 2: Основы React Native Глава 3: Создание пользовательского интерфейса с помощью React Native Глава 4:..

    Все о кейсах: Camel, Snake, Kebab & Pascal
    В программировании вы сталкивались с ними при именовании переменной, класса или функции. Поддержание согласованности типов и стилей случаев делает ваш код более читабельным и облегчает совместную..