Преобразование аннотаций XML в формат BRAT - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть аннотированный набор данных в формате XML: см. Пример ниже

Treatment of <annotation cui="C0267055">Erosive Esophagitis</annotation> in patients

где слова с тегами находятся в тегах XML, как показано. Мне нужно получить его в формате BRAT, например:

T1    annotation 14 33    Erosive Esophagitis

Дополнительные примеры можно найти в http://brat.nlplab.org/standoff.html

Я могу извлечь аннотации, используя регулярные выражения в Python, но я не уверен, как перевести их в правильный формат BRAT. Возможно, есть инструмент для этого?

1 Ответ

0 голосов
/ 05 мая 2019

Если кому-то все еще нужен ответ на этот вопрос, вот решение.

Допустим, XML-файл sample.xml имеет следующую структуру:

<root>
<p n='1'>Hi, my name is <fname>Mickey</fname> <lname>Mouse</lname>, and what about yourself?</p>
<p n='2'>Nice meeting you, <fname>Mickey</fname>! I am <fname>Minnie</lname>!</p>
</root>

Вот решение Python:

# leave empty if there are no tags that should not be interpreted as named entities; or add more
ignoretags = ['root', 'p']

# dictionary, in case some named entities have to be mapped; or just a list of tags that represent NEs
replacetags = {
    "fname": "PERS",
    "lname": "PERS"
}

# read content
content = open('sample.xml', encoding='utf-8').read()

# output files for BRAT: txt and annotations
f_txt = open('sample.txt', 'w')
f_ann = open('sample.ann', 'w')

# from txt file remove NE tags
clean_content = content
for replacetag in replacetags:
    clean_content = clean_content.replace('<{}>'.format(replacetag), '')
    clean_content = clean_content.replace('</{}>'.format(replacetag), '')

# write content to file
f_txt.write(clean_content)

# char by char
n = len(content)
i = - 1

# token id
tid = 0
# other - for output
start = -1
end = - 1
token = None
tag = None

# let's start parsing! character by character
skipped_chars = 0
number_of_tags = 0

token_buffer = ''
while i < n - 1:

    i += 1
    c = content[i]

    # beginning of an entity
    if c == '<':

    # probably the most important part: always track the count of skipped characters
        start = i - skipped_chars

        # get name of the entity
        tag_buffer = ''
        i += 1
        while content[i] != '>':
            tag_buffer += content[i]
            i += 1
        tag = tag_buffer

    # skip tags that are not NEs
        if tag not in replacetags:
            continue

        # get entity itself
        ent_buffer = ''
        i += 1
        while content[i] != '<':
            ent_buffer += content[i]
            i += 1
        token = ent_buffer

    # determine positions
        end = start + len(token)
        number_of_tags += 1

    # <fname></fname> i.e. 1 + len('fname') + 1 + 1 + 1 + len('fname') + 1
        skipped_chars += 1 + len(tag) + 1 + 1 + 1 + len(tag) + 1
        tid += 1

    # write annotation
        f_ann.write('T{}\t{} {} {}\t{}\n'.format(tid, replacetags[tag], start, end, token))

        # navigate to the end of the entity span, e.g. go behind <fname>...</fname>
        i += 1 + len(tag) + 1

Содержимое sample.txt

<root>
<p n='1'>Hi, my name is Mickey Mouse, and what about yourself?</p>
<p n='2'>Nice meeting you, Mickey! I am Minnie!</p>
</root>

Содержимое sample.ann:

T1  PERS 31 37  Mickey
T2  PERS 38 43  Mouse
T3  PERS 101 107    Mickey
T4  PERS 114 120    Minnie

И визуально в БРАТ:

BRAT visualization of sample.xml

В случае атрибутов понадобится небольшая настройка (я добавил еще один ключ 'att' в replacetags словаре, то есть пара будет тогда "fname": {"tag": "PERS", "att": "value of attribute"} и тогда в случае тега с атрибутом будет написана дополнительная строка.

Надеюсь, кто-нибудь найдет это полезным!

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