如何查看xml标签中没有文字内容的python?

How to check xml tags without text content in python?

我正在使用 Python 3.10 和 lxml 来验证由 VBA 宏生成的 xml 文件。但在此之前,我必须检查每个文件以查看树中是否有某些部分不包含任何文本内容(空白字符除外)以将其删除。

示例:

<n4ds:S10_G00_00>
        <n4ds:S10_G00_00_001>DGFIP-CAPU</n4ds:S10_G00_00_001>
        <n4ds:S10_G00_00_002>CUNOMF001_Janv2021</n4ds:S10_G00_00_002>
        <n4ds:S10_G00_00_003>v2022</n4ds:S10_G00_00_003>
        <n4ds:S10_G00_00_005>02</n4ds:S10_G00_00_005>
        <n4ds:S10_G00_00_006>P21V01</n4ds:S10_G00_00_006>
        <n4ds:S10_G00_00_008>01</n4ds:S10_G00_00_008>
        <n4ds:S10_G00_01>
            <n4ds:S10_G00_01_001>501975304</n4ds:S10_G00_01_001>
            <n4ds:S10_G00_01_002>26012</n4ds:S10_G00_01_002>
            <n4ds:S10_G00_01_003>NOMINATIF142021</n4ds:S10_G00_01_003>
            <n4ds:S10_G00_01_004>Avenue des Champs-Elysees</n4ds:S10_G00_01_004>
            <n4ds:S10_G00_01_005>93333</n4ds:S10_G00_01_005>
            <n4ds:S10_G00_01_006>BOURBOURG</n4ds:S10_G00_01_006>
            <n4ds:S10_G00_01_008>Z</n4ds:S10_G00_01_008>
            <n4ds:S10_G00_01_009>APT 25B</n4ds:S10_G00_01_009>
        </n4ds:S10_G00_01>
        <n4ds:S10_G00_02>
            <n4ds:S10_G00_02_001>01</n4ds:S10_G00_02_001>
            <n4ds:S10_G00_02_002>Pierre TOPAZE</n4ds:S10_G00_02_002>
            <n4ds:S10_G00_02_004>Emetteur@dgfip.fr</n4ds:S10_G00_02_004>
            <n4ds:S10_G00_02_005>0744215264</n4ds:S10_G00_02_005>
        </n4ds:S10_G00_02>
        <n4ds:S10_G00_95>
            <n4ds:S10_G00_95_001>LIART</n4ds:S10_G00_95_001>
            <n4ds:S10_G00_95_002>HAM-LES-MOINES</n4ds:S10_G00_95_002>
            <n4ds:S10_G00_95_003>50197530426012</n4ds:S10_G00_95_003>
            <n4ds:S10_G00_95_006>MtoM</n4ds:S10_G00_95_006>
            <n4ds:S10_G00_95_008>20210101091230</n4ds:S10_G00_95_008>
            <n4ds:S10_G00_95_900>2101NEORAUB3Message14CollectePH004</n4ds:S10_G00_95_900>
            <n4ds:S10_G00_95_901>netentreprises@gip.fr</n4ds:S10_G00_95_901>
        </n4ds:S10_G00_95>
        <n4ds:S20_G00_05 xsi:type="n4ds:Message_mensuel_des_revenus_autres">
            <n4ds:S20_G00_05_001>14</n4ds:S20_G00_05_001>
            <n4ds:S20_G00_05_002>01</n4ds:S20_G00_05_002>
            <n4ds:S20_G00_05_003>12</n4ds:S20_G00_05_003>
            <n4ds:S20_G00_05_004>250319523010</n4ds:S20_G00_05_004>
            <n4ds:S20_G00_05_005>2021-01-01</n4ds:S20_G00_05_005>
            <n4ds:S20_G00_05_007>2020-12-01</n4ds:S20_G00_05_007>
            <n4ds:S20_G00_05_009>IdMed001</n4ds:S20_G00_05_009>
            <n4ds:S20_G00_05_010>01</n4ds:S20_G00_05_010>
            <n4ds:S20_G00_07>
                <n4ds:S20_G00_07_001>VINCENT Tim</n4ds:S20_G00_07_001>
                <n4ds:S20_G00_07_002>0102030405</n4ds:S20_G00_07_002>
                <n4ds:S20_G00_07_003>Adresse@aol.fr</n4ds:S20_G00_07_003>
                <n4ds:S20_G00_07_004>10</n4ds:S20_G00_07_004>
            </n4ds:S20_G00_07>
            <n4ds:S20_G00_96>
                <n4ds:S20_G00_96_902>4</n4ds:S20_G00_96_902>
            </n4ds:S20_G00_96>
            <n4ds:S21_G00_06>
                <n4ds:S21_G00_06_001>508203890</n4ds:S21_G00_06_001>
                <n4ds:S21_G00_06_002>26012</n4ds:S21_G00_06_002>
                <n4ds:S21_G00_06_003>5510Z</n4ds:S21_G00_06_003>
                <n4ds:S21_G00_06_004>PLACE VENDOME</n4ds:S21_G00_06_004>
                <n4ds:S21_G00_06_005>92600</n4ds:S21_G00_06_005>
                <n4ds:S21_G00_06_006>ASNIERE</n4ds:S21_G00_06_006>
                <n4ds:S21_G00_06_903>CONSEIL PASRAU</n4ds:S21_G00_06_903>
                <n4ds:S21_G00_11>
                    <n4ds:S21_G00_11_001>31284</n4ds:S21_G00_11_001>
                    <n4ds:S21_G00_11_002>8423Z</n4ds:S21_G00_11_002>
                    <n4ds:S21_G00_11_003>RUE DU PARADIS</n4ds:S21_G00_11_003>
                    <n4ds:S21_G00_11_004>75010</n4ds:S21_G00_11_004>
                    <n4ds:S21_G00_11_005>ALBERVILLE</n4ds:S21_G00_11_005>
                    <n4ds:S21_G00_11_006>CEDEX 99</n4ds:S21_G00_11_006>
                    <n4ds:S21_G00_11_111>20210210</n4ds:S21_G00_11_111>
                    <n4ds:S21_G00_11_904>SRENOMINATIF</n4ds:S21_G00_11_904>
                    <n4ds:S21_G00_11_905>0</n4ds:S21_G00_11_905>


                    <n4ds:S21_G00_30>
                        <n4ds:S21_G00_31></n4ds:S21_G00_31>
                        <n4ds:S21_G00_47>
                            <n4ds:S21_G00_48></n4ds:S21_G00_48>
                        </n4ds:S21_G00_47>
                        <n4ds:S21_G00_50>
                            <n4ds:S21_G00_51></n4ds:S21_G00_51>
                            <n4ds:S21_G00_56></n4ds:S21_G00_56>
                        </n4ds:S21_G00_50>
                        <n4ds:S21_G00_97></n4ds:S21_G00_97>
                    </n4ds:S21_G00_30>



                </n4ds:S21_G00_11>
            </n4ds:S21_G00_06>
        </n4ds:S20_G00_05>
    </n4ds:S10_G00_00>

在这种情况下,为了验证我的文件,我需要删除 n4ds:S21_G00_30 和 之间的部分(以及标签本身)。

我试过这个代码:

pattern = "<n4ds:(.)+>(\s)*<\/n4ds:(.)+>"
repl = ''
def remove_empty_tags(file, pattern, repl):
    clean_lines = []
    with open(file, 'r') as fh:
        for line in fh:
            clean_lines.append(re.sub(pattern, repl, line))
    # Now save the file:
    with open(file, 'w') as fh:
        for line in clean_lines:
            fh.write(line)

但是我在找到正确的正则表达式时遇到了一些麻烦(将正则表达式与 XML/HTML 一起使用似乎不是一个好主意)。现在,它不处理嵌套标签。

我看到我可以使用 ElementTree 解析我的文件,但我找不到迭代和检查空树是否存在的解决方案。

如果有人知道我该如何解决这个问题,我会很乐意提供帮助。

此致。

Using regex with XML/HTML seems to be a bad idea

这是一个可怕的想法。

As it is right now, It doesn't deal with nested tags.

...这就是原因之一。

你说你有lxml。使用它。

可以在 XPath 中使用条件 normalize-space() = '' 找到除空格外没有文本的元素(即“空格规范化后为空”),以及没有子元素的元素使用 not(*)

很容易在循环中将它们从各自的父元素中移除。

from lxml import etree as ET

tree = ET.parse(r'C:\path\to\your\input.xml')

while True:
    empty_nodes = tree.xpath("//*[normalize-space() = '' and not(*)]")
    if not empty_nodes:
        break
    for node in empty_nodes:
        node.getparent().remove(node)

tree.write(r'C:\path\to\your\output.xml', pretty_print=True)

话虽这么说,因为您在那个 VBA 宏中使用 MSXML(对吗?),并且 MSXML 支持 XPath,所以您可以做完全相同的事情就在那时,没有将 XML 文件保存在 Python.

中需要 post-processing 的状态