连接 XML 标签成为数据框列名
Concatenate XML tags to become a dataframe column name
我目前正在解析一个 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'}]
,用'empty'填充父标签的值来标记它们,然后就可以串联了他们遵循的想法是,如果它找到 'empty' 值,则保存要连接的键,依此类推。
伙计们,我将不胜感激所有的帮助。非常感谢你提前。
棘手的部分是获取您感兴趣的元素的路径。使用 xslt 的一种方法是使用对模板的递归调用。
以下使用此方法 assemble 字典的字符串版本并将其交给 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>"}
</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>
使用 libxml 的 xsltproc 实用程序测试 xslt 转换:
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'}]
我目前正在解析一个 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'}]
,用'empty'填充父标签的值来标记它们,然后就可以串联了他们遵循的想法是,如果它找到 'empty' 值,则保存要连接的键,依此类推。
伙计们,我将不胜感激所有的帮助。非常感谢你提前。
棘手的部分是获取您感兴趣的元素的路径。使用 xslt 的一种方法是使用对模板的递归调用。
以下使用此方法 assemble 字典的字符串版本并将其交给 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>"}
</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>
使用 libxml 的 xsltproc 实用程序测试 xslt 转换:
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'}]