Как распечатать XML, созданный с использованием логического условия с помощью ElementMaker

#python #xml #lxml #pretty-print

#python #xml #lxml #pretty-print

Вопрос:

Как я могу избежать неправильного форматирования, если я не хочу генерировать E.note()?

Прямо сейчас все это работает, когда условие истинно, но когда оно равно False, в xml появляется пробел, что приводит к неправильному форматированию.

Одним из решений является использование etree.Подэлемент (xml, «примечание»), но я хотел избежать этого, потому что это заставляет меня продолжать использовать etree для всех последующих элементов.

Python 3
lxml: 4.5.2

 from lxml.builder import ElementMaker 
import lxml.etree as et

E = ElementMaker()

condition = False

xml = E.topic(
    E.first("first"),
    E.note("Text I want sometimes") if condition else "",
    E.third("third")
)

with open("result.xml", "wb") as f:
    f.write(et.tostring(xml.getroottree(), 
                          pretty_print=True,
                          xml_declaration=True, 
                          encoding='utf-8', 
                          standalone=False))
 

Результат, который я получаю:

 <?xml version='1.0' encoding='utf-8' standalone='no'?>
<topic><first>first</first><third>third</third></topic>
 

Но результат, который я хочу, это:

 <?xml version='1.0' encoding='utf-8' standalone='no'?>
<topic>
  <first>first</first>
  <third>third</third>
</topic>

 

Комментарии:

1. Я думаю, вам придется забыть ... if condition else ... и использовать subelement() или if condition: xml.append(E.note("Text I want sometimes"))

Ответ №1:

Я думаю, вы не можете ... if condition else ... этого сделать, и вам придется делать это более традиционным способом

 xml = E.topic()

xml.append(E.first("first"))

if condition:
    xml.append(E.note("Text I want sometimes"))

xml.append(E.third("third"))
 

в конце концов

 xml = E.topic(
    E.first("first"),
    E.third("third")
)

if condition:
    xml.insert(1, E.note('Text I want sometimes'))
 

Полный рабочий пример

 from lxml.builder import E  # ElementMaker 
import lxml.etree as et

#E = ElementMaker()

# --- functions ---

def display(xml):
    print(et.tostring(xml.getroottree(), 
                          pretty_print=True,
                          xml_declaration=True, 
                          encoding='utf-8', 
                          standalone=False).decode())

def example_0():
    xml = E.topic(
        E.first("first"),
        E.note("Text I want sometimes") if condition else "",
        E.third("third")
    )

    display(xml)
    
def example_1():
    xml = E.topic()

    xml.append(E.first("first"))

    if condition:
        xml.append(E.note("Text I want sometimes"))

    xml.append(E.third("third"))

    display(xml)

def example_2():
    xml = E.topic(
        E.first("first"),
        E.third("third")
    )

    if condition:
        xml.insert(1, E.note('Text I want sometimes'))

    display(xml)
    
# --- main ---

condition = False

example_0()
example_1()
example_2()
 

Комментарии:

1. Спасибо. Мне очень нравится, что вы показали как версию добавления, так и версию вставки. Я приму этот ответ.

2. Я также думал о reduce() том, чтобы удалить или [ ... for ... in ... if ...] удалить "" перед форматированием, но это не сработало.

Ответ №2:

Если сгенерированный XML проанализирован, pretty-printing работает. Таким образом, обходным путем является добавление одной строки кода непосредственно перед кодом, который записывает выходной файл:

 xml = et.fromstring(et.tostring(xml))
 

Если вы хотите, вы также можете упростить код, который записывает выходной файл:

 xml.getroottree().write("result.xml",
                        pretty_print=True,
                        xml_declaration=True, 
                        encoding='utf-8', 
                        standalone=False)