Python как убрать пробелы из текстовых узлов xml

У меня есть XML-файл следующим образом

<Person>
<name>

 My Name

</name>
<Address>My Address</Address>
</Person>

У тега есть дополнительные новые строки. Есть ли быстрый Pythonic способ обрезать это и генерировать новый xml.

Я нашел это, но это урезает только те, которые между тегами не значение https://skyl.org/log/post/skyl/2010/04/remove-insignificant-whitespace-from-xml-string-with-python/

Обновление 1 - Обработка следующего XML, который имеет хвостовые пространства в <name> тег

<Person>
<name>

 My Name<shortname>My</short>

</name>
<Address>My Address</Address>
</Person>

Дескриптор принятого ответа над обоими видами XML

Обновление 2 - я разместил свою версию в ответе ниже, я использую ее для удаления всех видов пробелов и создания довольно xml в файле с кодировками xml

/questions/42596994/python-kak-ubrat-probelyi-iz-tekstovyih-uzlov-xml/42597017#42597017

5 ответов

Решение

С lxml Вы можете перебрать все элементы и проверить, есть ли у него текст strip():

from lxml import etree

tree = etree.parse('xmlfile')
root = tree.getroot()

for elem in root.iter('*'):
    if elem.text is not None:
        elem.text = elem.text.strip()

print(etree.tostring(root))

Это дает:

<Person><name>My Name</name>
<Address>My Address</Address>
</Person>

ОБНОВЛЕНИЕ, чтобы раздеться tail текст тоже:

from lxml import etree

tree = etree.parse('xmlfile')
root = tree.getroot()

for elem in root.iter('*'):
    if elem.text is not None:
        elem.text = elem.text.strip()
    if elem.tail is not None:
        elem.tail = elem.tail.strip()

print(etree.tostring(root, encoding="utf-8", xml_declaration=True))

Принятый ответ, полученный Birei с использованием lxml, отлично справляется с этой задачей, но я хотел обрезать все виды белого / пустого пространства, пустых строк и восстановить довольно xml в файле xml.

Следующий код сделал то, что я хотел

from lxml import etree

#discard strings which are entirely white spaces
myparser = etree.XMLParser(remove_blank_text=True)

root = etree.parse('xmlfile',myparser)

#from Birei's answer 
for elem in root.iter('*'):
    if elem.text is not None:
        elem.text = elem.text.strip()
    if elem.tail is not None:
        elem.tail = elem.tail.strip()

#write the xml file with pretty print and xml encoding
root.write('xmlfile', pretty_print=True, encoding="utf-8", xml_declaration=True)

Вы должны сделать разбор XML для этого так или иначе, так что, возможно, используйте xml.sax и копировать в выходной поток при каждом событии (пропуск ignorableWhitespace) и добавьте маркеры тегов по мере необходимости. Проверьте пример кода здесь http://www.knowthytools.com/2010/03/sax-parsing-with-python.html.

Вы можете использовать Beautifulsoup. Обходите все элементы, и для каждого, который содержит некоторый текст, замените его его урезанной версией:

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xmlfile', 'r'), 'xml')

for elem in soup.find_all():
    if elem.string is not None:
        elem.string = elem.string.strip()

print(soup)

Если предположить, xmlfile с содержанием, представленным в вопросе, это дает:

<?xml version="1.0" encoding="utf-8"?>
<Person>
<name>My Name</name>
<Address>My Address</Address>
</Person>

Я работаю со старой версией Python (2.3), и в настоящее время я застрял в стандартной библиотеке. Чтобы показать ответ, который в значительной степени обратно совместим, я написал это с xml.dom а также xml.minidom функции.

import codecs
from xml.dom import minidom

# Read in the file to a DOM data structure.
original_document = minidom.parse("original_document.xml")

# Open a UTF-8 encoded file, because it's fairly standard for XML.
stripped_file = codecs.open("stripped_document.xml", "w", encoding="utf8")

# Tell minidom to format the child text nodes without any extra whitespace.
original_document.writexml(stripped_file, indent="", addindent="", newl="")

stripped_file.close()

Пока это не BeautifulSoup Это решение довольно элегантно и использует всю силу API нижнего уровня. Обратите внимание, что фактическое форматирование занимает всего одну строку:)

Документация по вызовам API, используемая здесь:

  • minidom.parse
  • minidom.Node.writexml
  • codecs.open
Другие вопросы по тегам