I am parsing ICD-10 codes and have achieved a result that satisfies my base case, but I'm worried about how fragile my method is:
import xml.etree.ElementTree as ET
# A sample of the larger XML file I'm parsing
data = '''<diag>
<name>A00</name>
<desc>Cholera</desc>
<diag>
<name>A00.0</name>
<desc>Cholera due to Vibrio cholerae 01, biovar cholerae</desc>
<inclusionTerm>
<note>Classical cholera</note>
</inclusionTerm>
</diag>
<diag>
<name>A00.1</name>
<desc>Cholera due to Vibrio cholerae 01, biovar eltor</desc>
<inclusionTerm>
<note>Cholera eltor</note>
</inclusionTerm>
</diag>
<diag>
<name>A00.9</name>
<desc>Cholera, unspecified</desc>
</diag>
</diag>'''
# Create the tree
tree = ET.ElementTree(ET.fromstring(data))
# the `iter` method returns all tags in a given tree
# I'm just grouping the tags and texts here
def get_all_elements(tree):
return [(elem.tag, elem.text) for elem in tree.iter()]
# This will return the desired elements from my tree
def parse_elements(tree):
# First, get all of the elements in the tree
elements = get_all_elements(tree)
to_return = {}
# This is what I think is too fragile. I'm basically looking
# ahead for each element to see whether the next two elements
# match the diag -> name -> desc sequence. But this indexing seems
# to be too fragile at scale.
for idx, elem in enumerate(elements):
if 'diag' in elem and 'name' in elements[idx+1] and 'desc' in elements[idx+2]:
name = elements[idx+1]
desc = elements[idx+2]
to_return[name[1]] = desc[1]
return to_return
res = parse_elements(tree)
Let's see what's in res
:
for k,v in res.items():
print("name (code): ", k, "\n desc: ", v)
name (code): A00.9
desc: Cholera, unspecified
name (code): A00.0
desc: Cholera due to Vibrio cholerae 01, biovar cholerae
name (code): A00
desc: Cholera
name (code): A00.1
desc: Cholera due to Vibrio cholerae 01, biovar eltor
So, I achieve my desired output, but I keep thinking there much be a better way to parse this XML. Unfortunately there's no <diag><subdiag></subdiag></diag>
-type of hierarchy. Even subdiagnoses are labeled with the <diag>
tag. I suppose the above is my attempt at recursion -- although I have found true recursion tough with the current tag-naming. At the end of the day, I just need the name: desc
pairs.
Edit:
There's also this approach:
names = [x.text for x in ET.fromstring(data).findall('.//name')]
descs = [x.text for x in ET.fromstring(data).findall('.//desc')]
res = zip(names, descs)
But I don't think this approach scales well, as the number of elements in names
and descs
differed by about 1000 when I tested this on the larger XML file. There were mismatches between codes and descriptions when I validated on actual codes.