如何用lxml的Element实现XML标签属性换行打印?
Great question! I’ve run into this exact issue with lxml before—its built-in pretty_print is great for indenting elements, but it doesn’t have a native setting to put each attribute on its own line. Let’s break down your options:
1. Use a Third-Party Library (Quickest Solution)
There are a few Python libraries designed specifically for custom XML formatting that can handle attribute-per-line output out of the box. My go-to is xmlformatter:
First, install it via pip:
pip install xmlformatter
Then use it to post-process your lxml output:
import xmlformatter from lxml import etree # Create your element as usual elem = etree.Element("module", name="A", description="abc", type="xyz") etree.SubElement(elem, "container") # Convert lxml element to raw XML string raw_xml = etree.tostring(elem, encoding="unicode") # Configure formatter to put one attribute per line formatter = xmlformatter.Formatter(indent=" ", attributes_per_line=1) formatted_xml = formatter.format_string(raw_xml) print(formatted_xml)
This will output exactly what you want:
<module name="A" description="abc" type="xyz"> <container/> </module>
Another option is the xmlformat command-line tool (which also has a Python API), but xmlformatter is more straightforward for programmatic use.
2. Manual Serialization (No Extra Dependencies)
If you don’t want to add a third-party library, you can write a simple recursive function to serialize the element yourself, with full control over attribute formatting:
from lxml import etree def format_xml_with_attr_newlines(elem, indent=" ", current_level=0): # Start the opening tag output = indent * current_level + f"<{elem.tag}" # Add each attribute on a new line, indented one level deeper for attr_name, attr_value in elem.attrib.items(): output += f"\n{indent * (current_level + 1)}{attr_name}=\"{attr_value}\"" # Handle child elements or self-closing tag children = list(elem) if children: output += ">\n" # Recursively format each child for child in children: output += format_xml_with_attr_newlines(child, indent, current_level + 1) # Add closing tag output += indent * current_level + f"</{elem.tag}>\n" else: # Self-closing tag output += "/>\n" return output # Test it out elem = etree.Element("module", name="A", description="abc", type="xyz") etree.SubElement(elem, "container") print(format_xml_with_attr_newlines(elem).strip())
This function will produce the same formatted output as the library approach, with no external dependencies.
Key Note About lxml
Just to confirm: lxml’s core etree.tostring() method doesn’t support this attribute formatting natively. The pretty_print flag only handles element indentation, not attribute line breaks—so you’ll need one of the above workarounds.
内容的提问来源于stack exchange,提问作者arpp

