Beautiful Soup 4 Пользовательский порядок вывода атрибутов - PullRequest
0 голосов
/ 28 января 2020

Я хочу создать пользовательский форматер вывода в BS4, который будет переставлять порядок атрибутов тегов в XML заданным образом c, это не алфавитный порядок.

Например, я хотите вывести следующий тег:

<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 форматер вывода, который будет оставлять атрибуты в порядке их ввода, а также игнорировать определенные теги, но я не знаю, как изменить это так, что он будет выводить в любом порядке, я бы хотел. Кто-нибудь может мне помочь?

Ответы [ 2 ]

2 голосов
/ 29 января 2020

Как насчет этого?

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"/>
0 голосов
/ 29 января 2020

Строго говоря, у меня есть ответ на свой вопрос, но потребуется больше работы, чтобы реализовать его так, как мне бы хотелось. Вот как это сделать.

Создайте подкласс XMLFormatter (или HTMLFormatter, если вы работаете с HTML), назовите его как хотите. Я выбрал «Сортировать атрибуты». Напишите функцию «attribute», чтобы она возвращала список кортежей: [(attribute1, value1), (attribute2, value2), et c.] В нужном вам порядке. Мой может выглядеть многословно, но я делаю это так, потому что я работаю с очень непоследовательным 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 переставляет атрибуты вернуться в алфавитный порядок. Вместо этого мне придется go подробнее узнать о подклассе XMLFormatter. Я надеюсь, что кто-то найдет это полезным в будущем!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...