首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >解析XML以获取所有elem.tag: elem.text对

解析XML以获取所有elem.tag: elem.text对
EN

Code Review用户
提问于 2017-02-06 16:47:56
回答 2查看 4K关注 0票数 2

我正在解析ICD-10码,并取得了满足基本情况的结果,但我担心我的方法是多么脆弱:

代码语言:javascript
运行
复制
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中的内容:

代码语言:javascript
运行
复制
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对。

编辑:

也有这样的方法:

代码语言:javascript
运行
复制
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文件上测试这个方法时,namesdescs中的元素数量相差了大约1000个。当我验证实际代码时,代码和描述之间有不匹配之处。

EN

回答 2

Code Review用户

回答已采纳

发布于 2017-02-06 19:56:26

由于后一种方法导致了不匹配对的断裂,所以似乎存在没有描述的代码。

如果只想捕获具有描述(现有desc节点)的诊断代码,可以使用以下XPath表达式强制执行此规则:

代码语言:javascript
运行
复制
.//diag[name and desc]

不过,问题是xml.etree.ElementTree 支持有限的XPath特性集和这个特定表达式要工作,您需要切换到lxml.etree。但是,它将带来性能提升,更好的内存使用和更丰富的功能。这是值得的。

还可以通过使用findtext()词典理解简化提取代码的方式:

代码语言:javascript
运行
复制
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)
票数 2
EN

Code Review用户

发布于 2017-02-06 19:52:18

XPath支持获取父元素https://docs.python.org/2/library/xml.etree.elementtree.html#supported-xpath-syntax。让我们尝试找到name元素并获得该元素的父元素:

代码语言:javascript
运行
复制
>>> [x for x in tree.findall('.//name/..')]
[<Element 'diag' at 0x7f9c8cece278>,
 <Element 'diag' at 0x7f9c85a84908>,
 <Element 'diag' at 0x7f9c85a93f98>,
 <Element 'diag' at 0x7f9c85a8f188>]

当我们有父元素时,我们可以得到namedesc元素:

代码语言:javascript
运行
复制
>>> [(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>)]

最后:

代码语言:javascript
运行
复制
>>> [(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')]
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/154603

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档