How to get correct text element in XML file

Viewed 107

I have the following xml child looking as follows:

<RollCallVote.Description.Text>
Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -
<a href="#reds:iPlRp/A-9-2021-0216" data-rel="reds" redmap-uri="/reds:iPlRp/A-9-2021-0216">A9-0216/2021</a>
- Nicolás González Casares - Accord provisoire - Am 156
</RollCallVote.Description.Text>

Now I try to get the following two elements, the redcap-uri text A9-0216/2021and the text behind that Nicolás González Casares - Accord provisoire - Am 156, ideally in two pandas data frame columns.

Unfortunately,

for adescription in avote.iter('RollCallVote.Description.Text'):
        description = adescription.get('a')

the data frame column in the end only gives me redcap-uribut not the text for it. Also changing it to description = adescription.get('a').text does not work, as I get the error message AttributeError: 'str' object has no attribute 'text'

If I use

for adescription in avote.iter('RollCallVote.Description.Text'):
        description = adescription.text

the beginning of the text, meaning Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -, is displayed in the end but nothing else.

Can someone please help to solve this, please?

2 Answers

When using ElementTree texts of interest could be extracted as follows:

import xml.etree.ElementTree as ET
from collections import defaultdict
import pandas as pd

content = '''<root>
<RollCallVote.Description.Text>
Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -
<a href="#reds:iPlRp/A-9-2021-0216" data-rel="reds" redmap-uri="/reds:iPlRp/A-9-2021-0216">A9-0216/2021</a>
- Nicolás González Casares - Accord provisoire - Am 156
</RollCallVote.Description.Text>
<RollCallVote.Description.Text>
Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -
<a href="#reds:iPlRp/A-9-2021-0216" data-rel="reds" redmap-uri="/reds:iPlRp/A-9-2021-0216">A9-0217/2021</a>
- Nicolás González Casares - Accord provisoire - Am 157
</RollCallVote.Description.Text>
<RollCallVote.Description.Text>
Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -
<a href="#reds:iPlRp/A-9-2021-0216" data-rel="reds" redmap-uri="/reds:iPlRp/A-9-2021-0216">A9-0218/2021</a>
- Nicolás González Casares - Accord provisoire - Am 158
</RollCallVote.Description.Text>
</root>'''

# create a dict to store temporary data
dct = defaultdict(list)

# parse XML
root = ET.fromstring(content)

# find elements with the given name
elements = root.findall('RollCallVote.Description.Text')

# iterate over elements found
for element in elements:
  # search for 'a' element having attribute 'redmap-uri'
  # if there is only one 'a' child element predictae can be omitted
  link = element.find('a[@redmap-uri]')
  if link:
      dct['link'].append(link.text)
      dct['text'].append(link.tail)

# construct pandas dataframe from a dict
df = pd.DataFrame(dct)

df

If you just want to extract some text from well-formatted xml code in a column (always the same structure), you can also try to solve it using regex instead of an xml parser:

import pandas as pd

df = pd.DataFrame({"text": """<RollCallVote.Description.Text>
Agence européenne des médicaments - European Medicines Agency - Europäische Arzneimittel-Agentur -
<a href="#reds:iPlRp/A-9-2021-0216" data-rel="reds" redmap-uri="/reds:iPlRp/A-9-2021-0216">A9-0216/2021</a>
- Nicolás González Casares - Accord provisoire - Am 156
</RollCallVote.Description.Text>
"""}, index=[0])

df["text"].str.extract(r'(.*?)\n<a .*>(.*?)<\/a>\n(.*?)\n<\/RollCallVote\.Description\.Text>', expand=True)

I just took the text and replaced the interesting parts with (.*?) capture groups (. is any char, * is any amount, so .* is any char, any amount. You can probably skip the ? after .*, but I just wanted to make sure it doesn't capture everything, which is what the ? does. The () brackets are a capture group, which is transformed to a column by .str.extract) and adding line breaks (\n) and escaping (adding \) dots (you need to tell regex if a dot is a dot and not an arbitrary char by writing \.).

Related