Search code examples
pythonxmllxmlpretty-print

How to pretty-print XML created using boolean condition with ElementMaker


How can I avoid bad formatting when I do not want to generate E.note()?

Right now it all works when condition is True, but when it is False it introduces space into the xml, which gives bad formatting.

One solution is to use etree.Subelement(xml, "note"), but I wanted to avoid this, because it forces me to continue using etree for all subsequent elements.

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))

The result I get:

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

But the result I want is:

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


Solution

  • I think you can't do this with ... if condition else ... and you will have to do it in more traditional way

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

    eventually

    xml = E.topic(
        E.first("first"),
        E.third("third")
    )
    
    if condition:
        xml.insert(1, E.note('Text I want sometimes'))
    

    Full working example

    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()