我正在尝试使用BeautifulSoup4解析一些旧的SGML代码,并使用数据构建一个元素树。大部分情况下都可以正常工作,但是某些应该自动关闭的标签并未这样标记。例如:
<element1>
<element2 attr="0">
<element3>Data</element3>
</element1>
当我解析数据时,它最终像:
<element1>
<element2 attr="0">
<element3>Data</element3>
</element2>
</element1>
我要假设的是,如果找不到此类元素的结束标记,则应将其视为自动结束标记,而不是假设其后的所有内容都是孩子,然后将结束标记尽可能晚地标记,就像这样:
<element1>
<element2 attr="0"/>
<element3>Data</element3>
</element1>
谁能指出我可以执行此操作的解析器,还是可以通过某种方式修改现有解析器以执行此操作?我已经研究了一些解析器(lxml,lxml-xml,html5lib),但是我不知道如何获得这些结果。
答案 0 :(得分:0)
我最终要做的是提取所有空元素,其中可以从DTD中省略结束标签(例如<!ELEMENT elem_name - o EMPTY >
),从这些元素创建一个列表,然后使用正则表达式关闭清单。然后将结果文本传递到XML解析器。
这是我正在做的事情的简化版本:
import re
from lxml.html import soupparser
from lxml import etree as ET
empty_tags = ['elem1', 'elem2', 'elem3']
markup = """
<elem1 attr="some value">
<elem2/>
<elem3></elem3>
"""
for t in empty_tags:
markup = re.sub(r'(<{0}(?:>|\s+[^>/]*))>\s*(?:</{0}>)?\n?'.format(t), r'\1/>\n', markup)
tree = soupparser.fromstring(markup)
print(ET.tostring(tree, pretty_print=True).decode("utf-8"))
输出应为:
<elem1 attr="some value"/>
<elem2/>
<elem3/>
(这实际上将包含在标记中,但解析器会将其添加到标记中。)
它将保留属性,并且不会触摸已经自封闭的标签。如果标签具有关闭标签,但为空,则会删除关闭标签并改为自动关闭标签,这就是标准化的做法。
这不是一个非常通用的解决方案,但是据我所知,没有其他方法可以在不知道应该关闭哪些标签的情况下进行。甚至OpenSP也需要DTD知道应该关闭哪些标签。