【问题标题】:How to extract nested values from XML with namespaces?如何使用命名空间从 XML 中提取嵌套值?
【发布时间】:2021-09-10 10:38:20
【问题描述】:

我正在尝试从以下 XML 文件中提取一些数据。

<?xml version="1.0" encoding="utf-8"?>
<go-home-1:GOHOMEV1 xmlns:go-home-1="https://sample.com/GO-HOME-V1">
    <HOMEV1FileHeader>
        <FileCreationTimestamp>2020-02-15T08:29:22+01:00</FileCreationTimestamp>
        <FileType>AB716</FileType>
        <SGO>YIFG</SGO>
    </HOMEV1FileHeader>
    <OI>
        <ON>YIFG4</ON>
        <CI>HYU</CI>
        <NL>
            <NT>
                <GOCode>HYU34</GOCode>
                <NTName>HYUFFT - 11</NTName>
                <NTData>
                    <RIS>
                        <RI>
                            <EDC>2020-01-18</EDC>
                            <E4NS>
                                <GNS>
                                    <RD>
                                        <NR>
                                            <CC>9012</CC>
                                            <NDC>411</NDC>
                                            <SRng>
                                                <SRngStart>000</SRngStart>
                                                <SRngStop>999</SRngStop>
                                            </SRng>
                                        </NR>
                                    </RD>
                                    <RD>
                                        <NR>
                                            <CC>834</CC>
                                            <NDC>101</NDC>
                                            <SRng>
                                                <SRngStart>150</SRngStart>
                                                <SRngStop>295</SRngStop>
                                            </SRng>
                                        </NR>
                                    </RD>
                                </GNS>
                            </E4NS>
                            <E2NS>
                                <MCC>111</MCC>
                                <MNC>222</MNC>
                            </E2NS>
                            <E2G>
                                <MGT_CC>9012</MGT_CC>
                                <MGT_NC>4113</MGT_NC>
                            </E2G>
                        </RI>
                    </RIS>
                </NTData>
            </NT>
        </NL>
    </OI>
</go-home-1:GOHOMEV1>

我的预期输出如下所示,将 SGO 作为第一个字段。

我的尝试如下(从这里获取想法Getting all children of a node using xml.etree.ElementTree) 但是我遇到了一些错误或空列表(对于sgo = root.find()...A = root.findall()...),我被困住了。感谢您的帮助。

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

filename = "file.xml"
namespaces = {
    "go-home-1": "https://sample.com/GO-HOME-V1"
}

root = ET.parse(filename).getroot()

# For this sgo = root.find()... I get ERROR << AttributeError: 'NoneType' object has no attribute 'text'>>
sgo = root.find("go-home-1:HOMEV1FileHeader/"
    "go-home-1:SGO", namespaces).text  

### For below I'm getting empty list A = [] and I don't know why.
A = root.findall(
    "go-home-1:OI/go-home-1:NL/go-home-1:NT[1]/go-home-1:NTData/go-home-1:RIS/go-home-1:RI/go-home-1:E4NS/"
    "go-home-1:GNS/"
    "go-home-1:RD/"
    "go-home-1:NR", namespaces)

for item1 in A:
    Result = [sgo]
    cc = item1.find("go-home-1:CC", namespaces).text
    ndc = item1.find("go-home-1:NDC", namespaces).text
    Result.append(cc)
    Result.append(ndc)
    
    B = item1.findall(
        "go-home-1:OI/go-home-1:NL/go-home-1:NT[1]/go-home-1:NTData/go-home-1:RIS/go-home-1:RI/go-home-1:E4NS/"
        "go-home-1:GNS/"
        "go-home-1:RD/"
        "go-home-1:NR/"
        "go-home-1:SRng", namespaces)
    
    for item2 in B:
    RngStart = item2.find("go-home-1:SRngStart", namespaces).text
    RngStop = item2.find("go-home-1:SRngStop", namespaces).text
    Result.append(RngStart)
    Result.append(RngStop)

    print(Result)

【问题讨论】:

  • xmlns:go-home-1="https://sample.com/GO-HOME-V1 命名空间声明仅适用于根元素。 XML 文档中的其他元素未绑定到命名空间。

标签: python-3.x xml elementtree xml-namespaces


【解决方案1】:

在这个特定的 xml 中,考虑到预期的输出,命名空间并不是真正需要的。此外,我认为呈现输出的最佳方式是使用数据框。

import pandas as pd

columns = ['SGO', 'MCC','MNC','MGT_CC','MGT_NC','CC','NDC','SRngStart','SRngStop']

sgo = root.find('.//SGO').text
mcc = root.find('.//MCC').text
mnc = root.find('.//MNC').text
mgt_cc = root.find('.//MGT_CC').text
mgt_nc = root.find('.//MGT_NC').text

rows = []
for entry in root.findall('.//RD'):
    row = []
    cc = entry.find('.//CC').text
    ndc = entry.find('.//NDC').text
    srngstart = entry.find('.//SRngStart').text
    srngstop = entry.find('.//SRngStop').text
    row.extend([sgo,mcc,mnc,mgt_cc,mgt_nc,cc,ndc,srngstart,srngstop])
    rows.append(row)

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

输出:

SGO     MCC     MNC     MGT_CC  MGT_NC  CC  NDC     SRngStart   SRngStop
0   YIFG    111     222     9012    4113    9012    411     000     999
1   YIFG    111     222     9012    4113    834     101     150     295

【讨论】:

  • 优秀。对于这个示例,它似乎工作得很好。我有个问题。由于存在具有不同父母的 CC、NDC 孩子(例如,E4NS 是这里的父母,但可能是父母 RHJ 与孩子 CC 和 NDC。为了获得这些,我应该使用更大的 xpath,如 .//E4NS/GNS/RD/NR/CC.//RHJ/GNS/RD/NR/CC ? 因为我已经尝试过这种方式但不起作用。谢谢
  • @Suspeg 这是可能的,但我需要一个较大的 xml 的代表性样本来确保。顺便说一句,您应该将其发布为新问题;我很乐意看看。
猜你喜欢
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 2011-08-19
  • 2014-09-27
  • 1970-01-01
  • 2016-05-14
相关资源
最近更新 更多