清理XML ==> 如果有空标签,则删除该行

6
我想清理我的 XML,使其不仅是有效的 XML,而且以一种非常易读的方式格式化。例如:
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition/>
</Items>

我希望删除任何不含内容的标签行,只留下如下内容:

<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
</Items>

我试着用正则表达式来实现这个功能,但是没有成功将它保留在易读的格式中:

txt = etree.tostring(self.xml_node, pretty_print=True)
txt = re.sub(r'<[a-zA-Z]+/>\n', '', txt)

如何最好地完成上述任务?

1
为什么不在它还是XML的时候就删除空节点,而不是在它变成字符串后再尝试删除? - jonrsharpe
“空标签”是什么意思?您是否指的是独立标签,即使它有属性? - user557597
使用正则表达式路由,这个可能会起作用 (?s)<[\w:]+(?:\s+(?:".*?"|'.*?'|[^>]*?)+)?/> - user557597
2个回答

11

使用XML解析器

思路是使用//*[not(node())] XPath表达式查找所有空节点,并从树中删除它们。例如,使用lxml

from lxml import etree


data = """
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition/>
</Items>
"""

root = etree.fromstring(data)
for element in root.xpath(".//*[not(node())]"):
    element.getparent().remove(element)

print etree.tostring(root, pretty_print=True)

1
这个解决方案可以考虑用于XML数据的n级深度。
from lxml import etree

def recursively_empty(xml_element):
   if xml_element.text:
       return False
   return all((recursively_empty(xe) for xe in xml_element.iterchildren()))

data = """
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition/>
</Items>
"""

xml_root = etree.iterwalk(data)

for action, xml_element in xml_root:
    parent = xml_element.getparent()
    if recursively_empty(xml_element):
        parent.remove(xml_element)

请注意:使用递归方法的原因是为了解决XML数据的多级深度问题。 解决方案应该适用于各种深度。
data1 = """
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition/>
</Items>
"""

data2 = """
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition>
        <cond1>Somedata</cond1>
    </Condition>
</Items>
"""

data3 = """
<Items>
    <Name>Hello</Name>
    <Cost>9.99</Cost>
    <Condition>
        </cond1>
    </Condition>
</Items>
"""

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接