我有以下 XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:okp="okapi-framework:xliff-extensions" xmlns:its="http://www.w3.org/2005/11/its" xmlns:itsxlf="http://www.w3.org/ns/its-xliff/" its:version="2.0">
<file original="temp/file_conversion/tmp4a9kn6bn/69502fea-751c-4c3c-a38a-4fce9e13ebde.txt" source-language="en" target-language="ar" datatype="x-text/plain" okp:inputEncoding="UTF-8">
<body>
<trans-unit id="1idhasofh" xml:space="preserve">
<source xml:lang="en">foo<bpt id="0"><bar></bpt><Instruction><ept id="0"><crow></ept><grande></source>
<target xml:lang="ar">foo<bpt id="0"><bar></bpt><Instruction><ept id="0"><crow></ept><grande></target>
</trans-unit>
</body>
</file>
</xliff>
我正在尝试创建一个函数来解析我已读入 ElementTree.Element 的 XML 文件:
from xml.etree import ElementTree as ET
def parse_xml(ele: ET.Element):
tag = ele.tag
if not isinstance(tag, str) and tag is not None:
return
t = ele.text
if t:
yield t
for e in ele:
parse_xml(e)
t = e.tail
if t:
yield t
def main():
fp = "path/to/xml"
tree = ET.parse(fp)
root = tree.getroot()
t_units = root.findall(".//{*}trans-unit")
for source, target in t_units:
for ele in parse_xml(source):
print(ele)
我得到:
foo
<Instruction>
<grande>
在我的调试器中,我看到
parse_xml(e)
被跳过。当我用打印语句替换产量时:
def parse_xml(ele: ET.Element):
tag = ele.tag
if not isinstance(tag, str) and tag is not None:
return
t = ele.text
if t:
print(t)
for e in ele:
parse_xml(e)
t = e.tail
if t:
print(t)
我得到了预期的结果(到达所有标记的文本):
foo
<bar>
<Instruction>
<crow>
<grande>
为什么yield会出现这种情况?
parse_xml
是一个生成器函数 - 当它被调用时,它不会运行:相反,它将返回一个必须迭代的生成器,就像对 parse_xml
的根调用在 for ele in parse_xml(source):
行中迭代一样在你的主要方法中。
此外,
parse_xml
调用会立即返回生成器,而不在函数内运行任何代码 - 它是 for
语句,它实际上运行函数内的代码并将其前进到 yield
语句。
因此,您可以在每个递归 parse_xml 调用中循环返回值,如下所示:
def parse_xml(ele: ET.Element):
...
for e in ele:
for inner_e in parse_xml(e):
yield inner_e
t = e.tail
if t:
yield t
或者,您可以使用 Python 的语法结构
yield from
来进行深层嵌套(或递归)生成器调用 - 这会更高效(并且对于使用其他功能的生成器还有其他优点,例如接受来自运行生成器的调用者函数)。这是推荐的方法:
def parse_xml(ele: ET.Element):
tag = ele.tag
if not isinstance(tag, str) and tag is not None:
return
t = ele.text
if t:
yield t
for e in ele:
yield from parse_xml(e)
t = e.tail
if t:
yield t
yield from
用于对parse_xml
的内部调用的返回值,如此处将做“正确的事情”:推迟外部(当前)parse_xml调用的执行,并隧道内部调用产生的每个值到它的调用者 - 当内部调用结束时(它产生一个 StopIteration
:与创建 for
循环相同的机制stop),外部调用的执行将恢复。