【问题标题】:Remove repeated data extracted from XML删除从 XML 中提取的重复数据
【发布时间】:2021-08-06 01:24:25
【问题描述】:

我正在尝试从 XML 文件中提取一些信息,并将其制成表格,如下图所示。我下面的代码几乎可以工作,但我被困在如何修复打印输出中出现的重复值(数据行)。下面我展示了当前输出、期望的输出、我到目前为止的代码和 xml 输入文件。感谢您的帮助。

  • 红色的数据是向下填充的值,因为在代码中使用了row.extend(...)

Python 代码

import xml.etree.ElementTree as ET
import glob, os
import pandas as pd

filename = 'input.xml'  
root = ET.parse(filename).getroot()

rows = []
columns = ['TC', 'LPP','LRP','LKTT','WQNT','ZZ','DFT','YY_TRWI','ZZ_TRWE']

for element in root.findall('.//NL/NW'):
    tc = element.find('.//TC').text
    llp = element.find('.//LPP').text
    lrp = element.find('.//LRP').text
    lktt = element.find('.//LKTT').text
    wqnt = element.find('.//WQNT').text
    
    for entry in root.findall('.//CEN4/GNR/RD/NR'):
        row = []
        zz = entry.find('.//ZZ').text
        dft = entry.find('.//DFT').text
        
        yy_trwi = getattr(entry.find('./SR/YY_TRWI'), 'text', None)
        zz_trwe = getattr(entry.find('./SR/ZZ_TRWE'), 'text', None)
        row.extend([tc,llp,lrp,lktt,wqnt,zz,dft,yy_trwi,zz_trwe])
        rows.append(row)

df = pd.DataFrame(rows, columns=columns)
df

XML 文件

<?xml version="1.0" encoding="UTF-8"?>
<vol-trf>
    <MAINXZ123FileHeader>
        <FT>XZ43</FT>
        <SNDTDG>AURUYYY</SNDTDG>
    </MAINXZ123FileHeader>
    <ON>
        <ORN>XYZ</ORN>
        <CI>AUR</CI>
        <NL>
            <NW>
                <TC>WEKP71</TC>
                <ND>
                    <RIS>
                        <RI>
                            <CEN4>
                                <GNR>
                                    <RD>
                                        <NR>
                                            <ZZ>403</ZZ>
                                            <DFT>676</DFT>
                                        </NR>
                                    </RD>
                                    <RD>
                                        <NR>
                                            <ZZ>419</ZZ>
                                            <DFT>170</DFT>
                                            <SR>
                                                <YY_TRWI>4001</YY_TRWI>
                                                <ZZ_TRWE>4015</ZZ_TRWE>
                                            </SR>
                                        </NR>
                                    </RD>
                                    <RD>
                                        <NR>
                                            <ZZ>429</ZZ>
                                            <DFT>170</DFT>
                                            <SR>
                                                <YY_TRWI>5574</YY_TRWI>
                                                <ZZ_TRWE>7614</ZZ_TRWE>
                                            </SR>
                                        </NR>
                                    </RD>
                                </GNR>
                            </CEN4>
                            <CEN2>
                                <LPP>2079</LPP>
                                <LRP>531</LRP>
                            </CEN2>
                            <CEM>
                                <LKTT>4113</LKTT>
                                <WQNT>5106</WQNT>
                            </CEM>
                        </RI>
                    </RIS>
                </ND>
            </NW>
            <NW>
                <TC>AURX45</TC>
                <ND>
                    <RIS>
                        <RI>
                            <CEN4>
                                <GNR>
                                    <RD>
                                        <NR>
                                            <ZZ>31</ZZ>
                                            <DFT>455</DFT>
                                        </NR>
                                    </RD>
                                    <RD>
                                        <NR>
                                            <ZZ>31</ZZ>
                                            <DFT>170</DFT>
                                            <SR>
                                                <YY_TRWI>123</YY_TRWI>
                                                <ZZ_TRWE>883</ZZ_TRWE>
                                            </SR>
                                        </NR>
                                    </RD>
                                    <RD>
                                        <NR>
                                            <ZZ>33</ZZ>
                                            <DFT>631</DFT>
                                            <SR>
                                                <YY_TRWI>324</YY_TRWI>
                                                <ZZ_TRWE>545</ZZ_TRWE>
                                            </SR>
                                        </NR>
                                    </RD>
                                </GNR>
                            </CEN4>
                            <CEN2>
                                <LPP>711</LPP>
                                <LRP>87</LRP>
                            </CEN2>
                            <CEM>
                                <LKTT>319</LKTT>
                                <WQNT>433</WQNT>
                            </CEM>
                        </RI>
                    </RIS>
                </ND>
            </NW>
        </NL>
    </ON>
</vol-trf>

【问题讨论】:

    标签: python-3.x xml elementtree


    【解决方案1】:

    这是按预期返回的(需要进行一些清理,但值是正确的)。
    所有 Xpath 表达式都使用祖先或兄弟值或位置来进行更精确的查询。 Xpath 位置从 1 开始,而不是 0。

    import xml.etree.ElementTree as ET
    from lxml import etree
    import pandas as pd
    
    filename = '/home/lmc/tmp/temp2.xml'
    root = etree.parse(filename)
    
    rows = []
    columns = ['TC','LPP','LRP','LKTT','WQNT','ZZ','DFT','YY_TRWI','ZZ_TRWE']
    
    i=0
    for element in root.xpath('//NL/NW/TC'):
    
        llp = element.xpath('//LPP/text()')
        lrp = element.xpath('//LRP')
        lktt = element.xpath('//LKTT')
        wqnt = element.xpath('//WQNT')
        y=0
        xp_base='//NW[TC[.="{}"]]'.format(element.text)
        xp='{}/descendant::CEN4/GNR/RD/NR'.format(xp_base)
        print(xp)
        for entry in element.xpath(xp):
            row = []
            xp_NR = '{}/descendant::NR[{}]'.format(xp_base, y+1)
            
            zz = entry.xpath('{}/descendant::ZZ/text()'.format(xp_NR))
            dft = entry.xpath('{}/descendant::DFT/text()'.format(xp_NR))
            
            
            xp = '{}/descendant::ZZ[.="{}"]/following-sibling::SR/YY_TRWI/text()'.format(xp_NR,zz[0])
            print(xp)
            yy_trwi = root.xpath(xp)
            xp = '{}/descendant::ZZ[.="{}"]/following-sibling::SR/ZZ_TRWE/text()'.format(xp_NR, zz[0])
            print(xp)
            zz_trwe = entry.xpath(xp)
            row.extend([element.text,llp[i],lrp[i].text,lktt[i].text,wqnt[i].text, zz, dft, yy_trwi, zz_trwe ])
            rows.append(row)
            y += 1
        
        i += 1
    
    df = pd.DataFrame(rows, columns=columns)
    print(df)
    

    结果:

           TC   LPP  LRP  LKTT  WQNT     ZZ    DFT YY_TRWI ZZ_TRWE
    0  WEKP71  2079  531  4113  5106  [403]  [676]      []      []
    1  WEKP71  2079  531  4113  5106  [419]  [170]  [4001]  [4015]
    2  WEKP71  2079  531  4113  5106  [429]  [170]  [5574]  [7614]
    3  AURX45   711   87   319   433   [31]  [455]      []      []
    4  AURX45   711   87   319   433   [31]  [170]   [123]   [883]
    5  AURX45   711   87   319   433   [33]  [631]   [324]   [545]
    

    打印一些 xpath 表达式 (xp)

    //NW[TC[.="WEKP71"]]/descendant::CEN4/GNR/RD/NR
    //NW[TC[.="WEKP71"]]/descendant::NR[1]/descendant::ZZ[.="403"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="WEKP71"]]/descendant::NR[1]/descendant::ZZ[.="403"]/following-sibling::SR/ZZ_TRWE/text()
    //NW[TC[.="WEKP71"]]/descendant::NR[2]/descendant::ZZ[.="419"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="WEKP71"]]/descendant::NR[2]/descendant::ZZ[.="419"]/following-sibling::SR/ZZ_TRWE/text()
    //NW[TC[.="WEKP71"]]/descendant::NR[3]/descendant::ZZ[.="429"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="WEKP71"]]/descendant::NR[3]/descendant::ZZ[.="429"]/following-sibling::SR/ZZ_TRWE/text()
    //NW[TC[.="AURX45"]]/descendant::CEN4/GNR/RD/NR
    //NW[TC[.="AURX45"]]/descendant::NR[1]/descendant::ZZ[.="31"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="AURX45"]]/descendant::NR[1]/descendant::ZZ[.="31"]/following-sibling::SR/ZZ_TRWE/text()
    //NW[TC[.="AURX45"]]/descendant::NR[2]/descendant::ZZ[.="31"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="AURX45"]]/descendant::NR[2]/descendant::ZZ[.="31"]/following-sibling::SR/ZZ_TRWE/text()
    //NW[TC[.="AURX45"]]/descendant::NR[3]/descendant::ZZ[.="33"]/following-sibling::SR/YY_TRWI/text()
    //NW[TC[.="AURX45"]]/descendant::NR[3]/descendant::ZZ[.="33"]/following-sibling::SR/ZZ_TRWE/text()
    

    【讨论】:

    • 感谢您的帮助。我试过了,但我收到错误AttributeError: 'xml.etree.ElementTree.Element' object has no attribute 'xpath'。我正在阅读这样的 xml f = open('input.xml') xml = f.read() f.close()
    • 抱歉,我将代码放入答案时出了点问题,现在应该可以了。我正在从字符串中读取您的示例,但从文件中读取应该没问题。
    • 非常感谢您的帮助。它似乎工作得很好。由于您的代码与我之前的代码非常相似,我想我可以进行一些自定义。我添加了类似zz1 = zz[0] if zz else "" 的行,以便删除zzdftyy_trwizz_trwe[..] 值。然后在row.extend([..., zz1, dft1,...])。我希望在所有情况下都是空列表或带有一个元素的列表。在那种情况下,我不会得到错误。
    • 很高兴它有帮助 :-) 让它工作很有趣。我相信 etree.xpath 总是返回一个列表,所以即使它只有一个元素,它也会是一个列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    相关资源
    最近更新 更多