Не удается прочитать sibling и дочерний элемент sibling из XML-файла

#python #xml #python-3.x #python-2.7 #xml-parsing

#python #xml #python-3.x #python-2.7 #xml-синтаксический анализ

Вопрос:

Я хотел прочитать PMID и имя автора из xml-файла, пример файла показан ниже

Я получаю PMID и forename, но цикл равен количеству повторений PMID, я хочу 1 PMID и соответствующее forename

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE PubmedArticleSet SYSTEM "http://dtd.nlm.nih.gov/ncbi/pubmed/out/pubmed_190101.dtd">
<PubmedArticleSet>
<PubmedArticle>
    <MedlineCitation Status="MEDLINE" Owner="NLM">
        <PMID Version="1">2844048</PMID>
        <AuthorList CompleteYN="Y">
            <Author ValidYN="Y">
                <LastName>Guarner</LastName>
                <ForeName>J</ForeName>
                <Initials>J</Initials>
            </Author>
            <Author ValidYN="Y">
                <LastName>Cohen</LastName>
                <ForeName>C</ForeName>
                <Initials>C</Initials>
            </Author>
            <Author ValidYN="Y">
                <LastName>Mushi</LastName>
                <ForeName>E</ForeName>
                <Initials>F</Initials>
            </Author>
        </AuthorList>
    </MedlineCitation>
</PubmedArticle>
<PubmedArticle>
    <MedlineCitation Status="MEDLINE" Owner="NLM">
        <PMID Version="1">123456</PMID>
        <AuthorList CompleteYN="Y">
            <Author ValidYN="Y">
                <LastName>Smith</LastName>
                <ForeName>C</ForeName>
                <Initials>C</Initials>
            </Author>
            <Author ValidYN="Y">
                <LastName>Jones</LastName>
                <ForeName>E</ForeName>
                <Initials>F</Initials>
            </Author>
        </AuthorList>
    </MedlineCitation>
</PubmedArticle>
</PubmedArticleSet>
  

код, я пытался

 FN=[]
for pmid in root.iter('PMID'):
    print(pmid.text)
    for id in root.findall("./PubmedArticle/MedlineCitation/Article/AuthorList"):
        for f in id.findall("./Author/ForeName"):
            fn=f.text

            x= '{},{}'.format(i, fn)
            #print(x)
            FN.append(x)
  

ожидаемый результат

 PMID               AUTHORS
2844048            'Guarner J J', 'Cohen C C'
  

Ответ №1:

Я не знаю, хотите ли вы, чтобы выходные данные были в определенном формате. Однако вы можете попробовать следующий код. На выходе получается словарь, где ключами являются PMID, а значениями — список авторов.

 import xml.etree.ElementTree as ET
import pandas as pd
tree = ET.parse('E:PythonDataFilesPMID.xml') # change according to your location
authors_pmid = []
all_authors_pmid = []
root = tree.getroot()
for amedlinecitation in root.iter('MedlineCitation'): #PMID and Author are childs of MedlineCitation
    pmid = amedlinecitation.find('PMID').text
    for anauthor in amedlinecitation.iter('Author'): # for each amedlinecitation, find all its Authors
        author_name = anauthor.find('LastName').text # for each Author, find the LastName tag and extract its value
        authors_pmid = [pmid,author_name]
        all_authors_pmid.append(authors_pmid)
df = pd.DataFrame(all_authors_pmid,columns=['PMID','Author'])
print(df)
  

Вывод:

 {'2844048': ['Guarner', 'Cohen', 'Mushi'], '123456': ['Smith', 'Jones']}
  

Следующий код выдаст выходные данные в табличной форме с использованием фрейма данных Python.

 import xml.etree.ElementTree as ET
import pandas as pd
tree = ET.parse('E:PythonDataFilesPMID.xml') # change according to your location
authors_pmid = []
all_authors_pmid = []
root = tree.getroot()
for amedlinecitation in root.iter('MedlineCitation'): #PMID and Author are childs of MedlineCitation
    pmid = amedlinecitation.find('PMID').text
    for anauthor in amedlinecitation.iter('Author'): # for each amedlinecitation, find all its Authors
        author_name = anauthor.find('LastName').text # for each Author, find the LastName tag and extract its value
        authors_pmid = [pmid,author_name]
        all_authors_pmid.append(authors_pmid)
df = pd.DataFrame(all_authors_pmid,columns=['PMID','Author'])
print(df)
  

Вывод:

       PMID   Author
0  2844048  Guarner
1  2844048    Cohen
2  2844048    Mushi
3   123456    Smith
4   123456    Jones
  

Чем приведенный выше код отличается от первого кода:

  1. Для каждой пары PMID и имени автора будет создан список. Этот список называется authors_pmid. Например, [‘2844048’, ‘Guarner’], [‘2844048’, ‘Cohen’], [‘2844048’, ‘Mushi’], [‘123456’, ‘Smith’], [‘123456’, ‘Jones’] будут значениями в переменной списка authors_pmid во время каждой итерации внутреннего цикла for.
  2. Затем каждый из приведенных выше списков будет добавлен к окончательному списку, определяемому all_authors_pmid
  3. Этот окончательный список будет данными, входящими в вызов конструктора Dataframe для создания Dataframe с именами столбцов как: PMID и Author

Комментарии:

1. Большое спасибо, {‘2844048’: [‘Guarner’, ‘Cohen’, ‘Mushi’], могу ли я получить входные данные типа 2844048’Guarner’ ‘2844048’: Cohen 2844048: Mushi?

2. При выполнении кода для всего файла я получаю ошибку AttributeError: объект ‘NoneType’ не имеет атрибута ‘text’, получая author_name = anauthor.find(‘ForeName’).text

3. Вы хотите получить выходные данные в виде словаря типа {2844048:’Guarner’, 2844048:’Cohen’, 2844048:’Mushi’}? Это невозможно, поскольку словарь имеет уникальные ключи. Таким образом, ключ 2844048 может появиться в словаре только один раз, и он будет иметь последнее введенное значение. Все значения, записанные ранее, будут перезаписаны новым значением. Если вы хотите, чтобы несколько значений принадлежали одному ключу, затем составьте список этих значений и присвоите его ключу. Это то, что делает мой приведенный выше код.

4. Что касается ошибки «AttributeError: объект ‘NoneType’ не имеет атрибута ‘text’, получая author_name = anauthor.find(‘ForeName’).text», мне трудно комментировать, не зная, какой код вы используете.

5. я решил ошибку атрибута, нет, я хочу ввести в dataframe, например, в одной строке 2844048’Guarner’, во 2-й строке 2844048: ‘Mushi. Возможно ли это?