BeautifulSoup漂亮打印自定义换行选项

9
我将使用BeautifulSoup来构建XML文件。
看起来我的两个选项是:1)没有格式,即
```html

我正在使用BeautifulSoup来构建XML文件。

似乎我的两个选项是1)没有格式

```
<root><level1><level2><field1>val1</field1><field2>val2</field2><field3>val3</field3></level2></level1></root>

或者2)使用prettify,即
<root>
 <level1>
  <level2>
   <field1>
    val1
   </field1>
   <field2>
    val2
   </field2>
   <field3>
    val3
   </field3>
  </level2>
 </level1>
</root>

但我更希望它看起来像这样:

但我更喜欢它看起来像这样:

<root>
    <level1>
        <level2>
            <field1>val1</field1>
            <field2>val2</field2>
            <field3>val3</field3>
        </level2>
    </level1>
</root>

我知道可以使用bs4进行修改来实现这个结果,但我想知道是否存在其他选项。 我不太关心四个空格的缩进(虽然那会很好),更在意任何闭合标签后面或两个开放标签之间的换行符。我也很好奇是否有一个名称来描述这种格式方式,因为这对我来说似乎是最合理的方式。

这篇关于编程的文章可能会对您有所帮助:https://dev59.com/GmUp5IYBdhLWcg3wHUvi。 - MikiBelavista
谢谢@MikiBelavista,但那个问题更关注缩进大小,而我最关心的是换行符,特别是仅在关闭标记后和两个开放标记之间有换行符。 - teebagz
1
@TommyGaboreau 如果使用简单的html.parser可以的话,请看我的答案。 - Andrej Kesely
1个回答

4
你可以使用简单的 html.HTMLParser 实现你想要的效果:
from bs4 import BeautifulSoup
from html import escape
from html.parser import HTMLParser

data = '''<root><level1><level2><field1>val1</field1><field2>val2</field2><field3>val3</field3></level2></level1></root>'''

class MyHTMLParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.__t = 0
        self.lines = []
        self.__current_line = ''
        self.__current_tag = ''

    @staticmethod
    def __attr_str(attrs):
        return ' '.join('{}="{}"'.format(name, escape(value)) for (name, value) in attrs)

    def handle_starttag(self, tag, attrs):
        if tag != self.__current_tag:
            self.lines += [self.__current_line]

        self.__current_line = '\t' * self.__t + '<{}>'.format(tag + (' ' + self.__attr_str(attrs) if attrs else ''))
        self.__current_tag = tag
        self.__t += 1

    def handle_endtag(self, tag):
        self.__t -= 1
        if tag != self.__current_tag:
            self.lines += [self.__current_line]
            self.lines += ['\t' * self.__t + '</{}>'.format(tag)]
        else:
            self.lines += [self.__current_line + '</{}>'.format(tag)]

        self.__current_line = ''

    def handle_data(self, data):
        self.__current_line += data

    def get_parsed_string(self):
        return '\n'.join(l for l in self.lines if l)


parser = MyHTMLParser()

soup = BeautifulSoup(data, 'lxml')
print('BeautifulSoup prettify():')
print('*' * 80)
print(soup.root.prettify())

print('custom html parser:')
print('*' * 80)
parser.feed(str(soup.root))
print(parser.get_parsed_string())

输出:

BeautifulSoup prettify():
********************************************************************************
<root>
 <level1>
  <level2>
   <field1>
    val1
   </field1>
   <field2>
    val2
   </field2>
   <field3>
    val3
   </field3>
  </level2>
 </level1>
</root>
custom html parser:
********************************************************************************
<root>
    <level1>
        <level2>
            <field1>val1</field1>
            <field2>val2</field2>
            <field3>val3</field3>
        </level2>
    </level1>
</root>

1
为了美化docx文档的xml输出,您的代码非常好用,只是我将soup.root替换为soup。 - El_1988

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