【问题标题】:How to parse XML nested value for multiple child group如何解析多个子组的 XML 嵌套值
【发布时间】:2021-01-17 09:59:32
【问题描述】:

我有一个很大的.xml 文件,其中的一部分如下所示:

<?xml version="1.0"?>
<data>
    <measData>
        <Mesurment Id="55">
            <granPeriod duration="1" endTime="2021-01-02"/>
            <repPeriod duration="1"/>
            <measTypes>73 74 574 75 35 36 </measTypes>
            <measValue measObj="Group1">
                <measResults>512 52.733 33.5 82 0 0 </measResults>
            </measValue>
            <measValue measObj="Group2">
                <measResults>512 78.175 50 119.5 0 0 </measResults>
            </measValue>
        </Mesurment>
    </measData>
</data>

我正在尝试从中解析出所需的数据并将其保存在 CSV 文件中。 我遇到的问题是,在 xml 文件中 &lt;measTypes&gt; 重复了一次,之后提到了 group1 和 Group2 的 &lt;measTypes&gt; 的值。 对于不同的&lt;Mesurment Id&gt;,它会有所不同,并且每个&lt;measTypes&gt; 报告的组值可能超过 10 个 问题出在这里,我不知道如何为一个measTypes 报告多个measResults 我有以下代码来获取值:

import xml.etree.ElementTree as ET
import pandas as pd
parsDict = dict()
tree = ET.parse('new.xml')
root = tree.getroot()

for itm in tree.iter():
    if (itm.tag.split('}')[-1] == 'Mesurment'):
        parsDict['Mesurment'] = [itm.attrib['Id']]
    if (itm.tag.split('}')[-1] == 'granPeriod'):
        parsDict['duration'] = [itm.attrib['duration']]
        parsDict['endTime'] = [itm.attrib['endTime']]
    if (itm.tag.split('}')[-1] == 'measTypes'):
        parsDict['CounterID'] = [itm.text]
    if (itm.tag.split('}')[-1] == 'measValue'):
        parsDict['measObj'] = [itm.attrib['measObj']]
    if (itm.tag.split('}')[-1] == 'measResults'):
        parsDict['value'] = [itm.text]
df2 = pd.DataFrame(parsDict)
df2.to_csv('123.csv',index=False)
print('finish')

结果如下

报告最新组 我想要的结果如下所示,需要能够扩展到多个组和测量 ID

【问题讨论】:

    标签: python xml pandas xml-parsing elementtree


    【解决方案1】:

    使用BeautifulSoup 库可能更容易做到这一点。在使用它之前,您应该安装这些依赖项:

    beautifulsoup4 = "4.9.3"
    lxml = "^4.6.1"
    
    from bs4 import BeautifulSoup, Tag
    
    soup = BeautifulSoup("""
    <?xml version="1.0"?>
    <data>
        <measData>
            <Mesurment Id="55">
                <granPeriod duration="1" endTime="2021-01-02"/>
                <repPeriod duration="1"/>
                <measTypes>73 74 574 75 35 36 </measTypes>
                <measValue measObj="Group1">
                    <measResults>512 52.733 33.5 82 0 0 </measResults>
                </measValue>
                <measValue measObj="Group2">
                    <measResults>512 78.175 50 119.5 0 0 </measResults>
                </measValue>
            </Mesurment>
        </measData>
    </data>
    """, features="xml")
    
    response = []
    
    for tag in soup.data.measData:
        if not isinstance(tag, Tag):
            continue
        
        # please, update this dict with all the top level attributes you need
        data = {"duration": tag.granPeriod.attrs["duration"], }
    
        for measValue in tag:
            if not isinstance(measValue, Tag) or getattr(measValue, "measResults") is None:
                continue
    
            response.append({
                **data,
                "measObj": measValue.attrs["measObj"],
                "value": measValue.measResults.text
            })
    
    print(response)
    
    

    更新

    使用你做的库,可以这样做:

    import xml.etree.ElementTree as ET
    import pandas as pd
    
    tree = ET.parse('new.xml')
    root = tree.getroot()
    
    response = []
    
    for mesurment in tree.iter("Mesurment"):
        granPeriod = next(
            it for it in mesurment if it.tag == "granPeriod"
        )
        measTypes = next(
            it for it in mesurment if it.tag == "measTypes"
        )
        measValues = [it for it in mesurment if it.tag == "measValue"]
    
        mesurment_data = {
            "Mesurment": mesurment.attrib["Id"],
            "duration": granPeriod.attrib["duration"],
            "endTime": granPeriod.attrib["endTime"],
            "CounterId": measTypes.text,
        }
    
        for value in measValues:
            response.append({
                **mesurment_data,
                "measObj": value.attrib["measObj"],
                "value": next(
                    it.text for it in value if it.tag == "measResults"
                )
            })
    
    df2 = pd.DataFrame(response)
    print(df2)
    

    【讨论】:

    • 我不想在我的代码中添加另一个包,也可以加快解析另一个问题的速度
    • @Mohsen 我更新了我的答案,这就足够了
    • 谢谢,它适用于扩展数据,但我的原始文件有问题,错误是:it for it in mesurment if it.tag == "granPeriod" StopIteration
    • @Mohsen 如果特定测量的标签不存在,则可能会发生这种情况。在这种情况下,只需将所有next 语句转换为这种格式next((it for it in mesurment if it.tag == "granPeriod"), None)。所以如果它没有找到任何标签,它会返回一个无。然后你会有一个 if 语句来检查它是否存在,所以它不会在这一行失败granPeriod.attrib["duration"]
    猜你喜欢
    • 2017-03-30
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多