Python XML/Pandas:如何合并嵌套的XML



如何将该XML文件中的两条不同信息连接在一起?

# data
xml1 = ('''<?xml version="1.0" encoding="utf-8"?>
<TopologyDefinition xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RSkus>
<RSku ID="V1" Deprecated="true" Owner="Unknown" Generation="1">
<Devices>
<Device ID="1" SkuID="Switch" Role="xD" />
</Devices>
<Blades>
<Blade ID="{1-20}" SkuID="SBlade" />
</Blades>
<Interfaces>
<Interface ID="COM" HardwareID="NS1" SlotID="COM1" Type="serial" />
<Interface ID="LINK" HardwareID="TS1" SlotID="UPLINK_1" Type="serial" />
</Interfaces>
<Wires>
<WireGroup Type="network">
<Wire LocationA="NS1" SlotA="{1-20}" LocationB="{1-20}" SlotB="NIC1" />
</WireGroup>
<WireGroup Type="serial">
<Wire LocationA="TS1" SlotA="{7001-7020}" LocationB="{1-20}" SlotB="COM1" />
</WireGroup>
</Wires>
</RSku>
</RSkus>
</TopologyDefinition>
''')

虽然这是一个单一的案例,在下面的例子中很琐碎;如果我在整个文件上运行以下命令,我会得到不匹配的形状,因此无法如此容易地连接。

如何提取XML信息,使每一行都获得所有RSku信息及其Blade信息。每个xpath都不包含允许我将其加入另一个xpath的信息,这样我就可以组合这些信息。

# how to have them joined?
pd.read_xml(xml1, xpath = ".//RSku")
pd.read_xml(xml1, xpath = ".//Blade")
# expected
pd.concat([pd.read_xml(xml1, xpath = ".//RSku"), pd.read_xml(xml1, xpath = ".//Blade")], axis=1)

考虑使用XSLT转换XML,方法是用所需信息对文档进行扁平化。具体而言,使用descendant::*轴仅检索Blade属性,并使用ancestor::*轴检索相应的RSku特性。Python的lxml(pandas.read_xml的默认解析器(可以运行XSLT1.0脚本。

下面XSLT的<xsl:for-each>用于将RSku_Blade_作为属性名称的前缀,因为它们共享相同的属性,例如ID。否则模板就不会那么冗长了。

import pandas as pd
xml1 = ...
xsl = ('''<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
version="1.0">  
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/TopologyDefinition">
<root>
<xsl:apply-templates select="descendant::Blade"/>
</root>
</xsl:template>

<xsl:template match="Blade">
<data>
<xsl:for-each select="ancestor::RSku/@*">
<xsl:attribute name="{concat('RSku_', name())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:for-each select="@*">
<xsl:attribute name="{concat('Blade_', name())}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</data>
</xsl:template>

</xsl:stylesheet>''')
blades_df = pd.read xml(xml1, stylesheet=xsl)

在线XSLT演示

最新更新