[我想在BS4中创建一个自定义输出格式化程序,它将以一种不是字母顺序的特定方式重新排列XML中标记属性的顺序。
例如,我要输出以下标签:
<word form="συ" head="2610" id="2357" lemma="συ" postag="p-s----n-" relation="ExD_AP"/>
as:
<word id="2357" head="2610" postag="p-s----n-" form="συ" lemma="συ" relation="ExD_AP"/>
BS4的文档提供了从哪里开始的线索。他们给出了以下示例:
from bs4.formatter import HTMLFormatter
class UnsortedAttributes(HTMLFormatter):
def attributes(self, tag):
for k, v in tag.attrs.items():
if k == 'm':
continue
yield k, v
print(attr_soup.p.encode(formatter=UnsortedAttributes()))
这将创建一个自定义HTML输出格式化程序,该格式化程序将按输入属性的顺序保留属性,并忽略某些标签,但是我不知道如何更改此格式,以便按我希望的顺序输出。谁能帮帮我?
怎么样?
from simplified_scrapy.simplified_doc import SimplifiedDoc
html ='''
<word form="συ" head="2610" id="2357" lemma="συ" postag="p-s----n-" relation="ExD_AP"/>
'''
def toString(ele):
order = ['id','head','postag','from','lemma','relation']
result = '<'+ele.tag
for p in order:
result+=' {}="{}"'.format(p,ele[p])
return result+'/>'
doc = SimplifiedDoc(html)
ele = doc.word
print (toString(ele))
结果:
<word id="2357" head="2610" postag="p-s----n-" from="None" lemma="συ" relation="ExD_AP"/>
严格来说,我对自己的问题有一个答案,但是要以我希望的方式实际实施它需要更多的工作。这是操作方法。
作为XMLFormatter(如果使用HTML,则为HTMLFormatter)的子类,将其命名为所需的名称。我选择了“ SortAttributes”。编写函数“ attributes”,以便它将按所需顺序返回元组列表:[[(attribute1,value1),(attribute2,value2)等]。我的看起来可能很冗长,但我这样做是因为我使用的是非常不一致的XML。
from bs4 import BeautifulSoup
from bs4.formatter import XMLFormatter
class SortAttributes(XMLFormatter):
def attributes(self, tag):
"""Reorder a tag's attributes however you want."""
attrib_order = ['id', 'head', 'postag', 'relation', 'form', 'lemma']
new_order = []
for element in attrib_order:
if element in tag.attrs:
new_order.append((element, tag[element]))
for pair in tag.attrs.items():
if pair not in new_order:
new_order.append(pair)
return new_order
xml_string = '''
<word form="συ" head="2610" id="2357" lemma="συ" postag="p-s----n-" relation="ExD_AP"/>
'''
soup = BeautifulSoup(xml_string, 'xml')
print(soup.encode(formatter=SortAttributes()))
这将输出我想要的:
<word id="2357" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/>
方便地,我可以使用相同的编码方法对整个文档执行此操作。但是,如果我以字符串形式将其写入文件,则所有标签都将首尾相连。样本如下:
<sentence id="783"><word id="2357" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/><word id="2358" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/><word id="2359" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/></sentence>
而不是我想要的东西:
<sentence id="783">
<word id="2357" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/>
<word id="2358" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/>
<word id="2359" head="2610" postag="p-s----n-" relation="ExD_AP" form="συ" lemma="συ"/>
</sentence>
要解决这个问题,我不能只是.prettify它,因为prettify将属性重新排列为字母顺序。我将不得不使用XMLFormatter子类进入更多细节。希望以后有人对您有所帮助!