我正在解析ICD-10码,并取得了满足基本情况的结果,但我担心我的方法是多么脆弱:
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)让我们看看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因此,我实现了我想要的输出,但我一直认为有更好的方法来解析这个XML。不幸的是,没有层次结构的<diag><subdiag></subdiag></diag>-type。即使是子诊断也用<diag>标记。我想以上是我对递归的尝试--尽管我发现当前标记命名的真正递归很难。在一天结束时,我只需要name: desc对。
编辑:
也有这样的方法:
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)但是,我不认为这种方法有很好的扩展性,因为当我在更大的XML文件上测试这个方法时,names和descs中的元素数量相差了大约1000个。当我验证实际代码时,代码和描述之间有不匹配之处。
发布于 2017-02-06 19:56:26
由于后一种方法导致了不匹配对的断裂,所以似乎存在没有描述的代码。
如果只想捕获具有描述(现有desc节点)的诊断代码,可以使用以下XPath表达式强制执行此规则:
.//diag[name and desc]不过,问题是xml.etree.ElementTree 支持有限的XPath特性集和这个特定表达式要工作,您需要切换到lxml.etree。但是,它将带来性能提升,更好的内存使用和更丰富的功能。这是值得的。
还可以通过使用findtext()和词典理解简化提取代码的方式:
from pprint import pprint
import lxml.etree as ET
data = """your XML here"""
root = ET.fromstring(data)
result = {diag.findtext("name"): diag.findtext("desc")
for diag in root.xpath(".//diag[name and desc]")}
pprint(result)发布于 2017-02-06 19:52:18
XPath支持获取父元素https://docs.python.org/2/library/xml.etree.elementtree.html#supported-xpath-syntax。让我们尝试找到name元素并获得该元素的父元素:
>>> [x for x in tree.findall('.//name/..')]
[<Element 'diag' at 0x7f9c8cece278>,
<Element 'diag' at 0x7f9c85a84908>,
<Element 'diag' at 0x7f9c85a93f98>,
<Element 'diag' at 0x7f9c85a8f188>]当我们有父元素时,我们可以得到name和desc元素:
>>> [(x.find('name'), x.find('desc')) for x in tree.findall('.//name/..')]
[(<Element 'name' at 0x7f9c875ba7c8>, <Element 'desc' at 0x7f9c8cedfe58>),
(<Element 'name' at 0x7f9c85a84958>, <Element 'desc' at 0x7f9c85a84f98>),
(<Element 'name' at 0x7f9c85a8f048>, <Element 'desc' at 0x7f9c85a8f098>),
(<Element 'name' at 0x7f9c85a8f1d8>, <Element 'desc' at 0x7f9c85a8f228>)]最后:
>>> [(x.find('name').text, x.find('desc').text) for x in tree.findall('.//name/..')]
[('A00', 'Cholera'),
('A00.0', 'Cholera due to Vibrio cholerae 01, biovar cholerae'),
('A00.1', 'Cholera due to Vibrio cholerae 01, biovar eltor'),
('A00.9', 'Cholera, unspecified')]https://codereview.stackexchange.com/questions/154603
复制相似问题