Объединить теги XML, чтобы они стали именем столбца данных - PullRequest
0 голосов
/ 17 октября 2019

В настоящее время я анализирую XML, и после этого заполняю фрейм данных. Предположим, у нас есть этот игрушечный XML:

<A>
  <AA>
      <AAA1 period='march'>ONE</AAA1>
      <AAA2>TWO</AAA2>
      <AAA3>THREE</AAA3>
      <AAA4>
           <B semester='4'>FOUR</B>
           <C>FIVE</C>
           <D>SIX</D>
      </AAA4>
  </AA>
</A>

И я пытаюсь получить что-то вроде: [{A.AA.AAA1.period-march: 'ONE'}, {A.AA.AAA2: 'TWO'}, {A.AA.AAA3: 'THREE'}, {A.AA.AAA4.B.semester-4: 'FOUR'},{A.AA.AAA4.C: 'FIVE'}, {A.AA.AAA4.D: 'SIX'}], с которым было бы намного проще работать.

Я уже проанализировалXML и преобразовал его в эту форму: [{'A: 'empty'}, {'AA': 'empty'}, {'AAA1': 'ONE'}, {'AAA2': 'TWO'},{'AAA3': 'THREE'}, {'AAA4': 'empty'}, {'B': 'FOUR'}, {'C': 'FIVE'}, {'D': 'SIX'}], заполнив значения родительских тегов «пустым», чтобы пометить их, а затем иметь возможность объединить их, следуя идее, что, если он найдет и «пустое» значение, сохранит ключобъединить и т. д.

Буду признателен за помощь, ребята. Заранее большое спасибо.

1 Ответ

1 голос
/ 18 октября 2019

Сложная задача - получить путь к интересующему вас элементу. Одним из способов использования xslt является использование рекурсивного вызова шаблона.

Следующий метод использует этот метод для сборки строковых версий словарей и передачи их в python.

Вот часть xslt, dataframe.xsl:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" />
    <xsl:strip-space elements="*" />

    <!-- match all elements that have text -->
    <xsl:template match="//*[text()]">
        <xsl:text>{'</xsl:text>
        <xsl:call-template name="pwd" />
        <xsl:text>': "</xsl:text>
        <xsl:value-of select="normalize-space(.)" />
        <xsl:text>"}&#xa;</xsl:text>
    </xsl:template>

    <!-- recursive template that prints parent element names -->
    <xsl:template name="pwd">
        <xsl:for-each select="parent::*">
            <xsl:call-template name="pwd" />
        </xsl:for-each>
        <xsl:if test="count(ancestor::*) > 0">
            <xsl:text>.</xsl:text>
        </xsl:if>
        <xsl:value-of select="name()" />
        <xsl:for-each select="@*">
            <xsl:value-of select="concat('.', name(), '-', .)" />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Для проверкипреобразование xslt с помощью утилиты libxml xsltproc:

xsltproc dataframe.xsl source.xml
{'A.AA.AAA1.period-march': 'ONE'}
{'A.AA.AAA2': 'TWO'}
{'A.AA.AAA3': 'THREE'}
{'A.AA.AAA4.B.semester-4': 'FOUR'}
{'A.AA.AAA4.C': 'FIVE'}
{'A.AA.AAA4.D': 'SIX'}

Соберите все это вместе в python, dataframe.py:

#!/usr/bin/env python3
import ast
from lxml import etree

with open('dataframe.xsl') as stylesheet:
    transform = etree.XSLT(etree.XML(stylesheet.read()))

with open('source.xml') as xml:
    dataframe_str = str(transform(etree.parse(xml))).rstrip('\n')

dataframe_array = list(map(lambda s: ast.literal_eval(s),
    dataframe_str.split('\n')))

print(dataframe_array)

Результаты:

./dataframe.py
[{'A.AA.AAA1.period-march': 'ONE'}, {'A.AA.AAA2': 'TWO'}, {'A.AA.AAA3': 'THREE'}, {'A.AA.AAA4.B.semester-4': 'FOUR'}, {'A.AA.AAA4.C': 'FIVE'}, {'A.AA.AAA4.D': 'SIX'}]
...