声明:
lxml
和iter()
,以及iterparse()
,我已经尝试了this way和this way。它对我没有用。我这样做。一路走来;这段代码可以工作并完成我想要它做的事情,这基本上是采用一大堆xml记录并将其转换为{ record_id : {element_tag : element_val, element_tag : element_val, ...} }
形式的字典。
由于record_id嵌套在记录本身中,我首先使用record_splitter
来确定<RECORD>
和</RECORD>
(beg
和end
的计数})。我将beg
和end
传递给找到这些位置的dic_factory
,对嵌套在其中的元素执行某些操作,然后设置“乞讨”。到end +1
,然后将其传回record_splitter
函数。
我的问题是否有更好的方法在函数之间实现此循环,最好是在if __name__ == '__main__'
下,以便我可以移动更多的常量(例如正则表达式语句)那也是。
Code:
# stored as a text file, but here for clarity
list_of_lines = """
<RECORD>
<TITLE>MISS</TITLE>
<NAME>ELIZABETH</NAME>
<SURNAME>II</SURNAME>
<ADDRESS1>1 BUCKINGHAM PALACE</ADDRESS1>
<ADDRESS2>LONDON</ADDRESS2>
<ADDRESS3>GREATER LONDON</ADDRESS3>
<POST_CODE>W1 11A</POST_CODE>
<CASE_NUM>Q1QQ1234</CASE_NUM>
<ID>32145698</ID>
<LAST_UPDATE_DATE>2016-12-12</LAST_UPDATE_DATE>
</RECORD>
<RECORD>
<TITLE>MR</TITLE>
<NAME>PRINCE</NAME>
<SURNAME>PHILLIP</SURNAME>
<ADDRESS1>1 BUCKINGHAM PALACE</ADDRESS1>
<ADDRESS2>LONDON</ADDRESS2>
<ADDRESS3>GREATER LONDON</ADDRESS3>
<POST_CODE>W1 11A</POST_CODE>
<CASE_NUM>K5KK4321</CASE_NUM>
<ID>56987412</ID>
<LAST_UPDATE_DATE>2017-01-16</LAST_UPDATE_DATE>
</RECORD>
<RECORD>
"""
class recordManager:
def __init__(self):
self.r_location = "list_of_lines.txt"
def record_splitter(self, beg):
re_beg_spl = re.compile(".*<RECORD>")
re_end_spl = re.compile(".*(<\\/RECORD>)")
end = None
for count, line in enumerate( open(self.r_location) ):
if count > beg:
if re_end_spl.match(line):
end = count
if not re_end_spl.match(line):
if re_beg_spl.match(line):
beg = count
else:
break
recordManager.dic_factory(self, beg, end)
def dic_factory(self, beg, end):
re_casenum = re.compile(".*<CASE_NUM>(.*)<\\/CASE_NUM>")
re_tag_val = re.compile(".*<(\\w*)>(.*)<.*")
id_ = None
tags = []
vals = []
for count, line in enumerate( open(self.r_location) ):
if beg < count < end:
if re_casenum.match(line):
m = re_casenum.match(line)
id_ = m.group(1)
if re_tag_val.match(line):
m = re_tag_val.match(line)
tags.append( m.group(1) )
vals.append( m.group(2) )
beg = end +1
print {id_ : dict(zip(tags, vals)) }
# {32145698 : {'POST_CODE': 'W1 11A', 'SURNAME': 'II', 'NAME': 'ELIZABETH', 'TITLE': 'MISS', 'ADDRESS1': '1 BUCKINGHAM PALACE', 'ADDRESS2': 'LONDON', 'ADDRESS3': 'GREATER LONDON', 'RECORD_TYPE': '1', 'CASE_NUM': 'Q1QQ1234', 'LAST_UPDATE_DATE': '2016-12-12', 'ID': '32145698'}}
self.record_splitter(beg)
if __name__ == '__main__':
inst_fol = record_manager(file)
recordManager.record_splitter(inst_folder, 0)
我的问题是,我不知道如何循环“乞讨”。返回到函数之外的record_splitter
/来自 main :
if __name__ == '__main__':
inst_fol = record_manager(file)
beg, end = recordManager.record_splitter(inst_folder, 0)
这是&#34;从函数内循环#34;如果不是,那么更好的方法是什么?
答案 0 :(得分:1)
tl; dr:用self.beg替换beg
我的建议是让beg
成为你班上的一个字段。请记住,您使用的每种方法都可以访问self
,这是将该工作组织到一个类中的优势的一部分:
所以__init__
变为:
def __init__(self):
self.r_location = "list_of_lines.txt"
self.beg = 0
现在,无论您在哪里使用beg
,都可以将其称为self.beg
。
例如:
for count, line in enumerate( open(self.r_location) ):
if count > self.beg:
if re_end_spl.match(line):
end = count
if not re_end_spl.match(line):
if re_beg_spl.match(line):
self.beg = count
else:
break
recordManager.dic_factory(self, self.beg, end)
请注意,还有进一步整合的机会:
dic_factory
将beg
作为参数,但它也可以访问对象self
,并且只能从该字段读取beg
。
答案 1 :(得分:1)
我建议您在同一个迭代器上使用嵌套循环而不是单独的函数。 (评论中的详细信息)..
class recordManager:
def __init__(self):
self.r_location = "list_of_lines.txt"
self.records = [] #perhaps we want to store all the records we find?
def find_records(self):
re_beg_spl = re.compile(".*<RECORD>")
re_end_spl = re.compile(".*(<\\/RECORD>)")
re_casenum = re.compile(".*<CASE_NUM>(.*)<\\/CASE_NUM>") #move these up here since we're rolling the two functions into one
re_tag_val = re.compile(".*<(\\w*)>(.*)<.*")
with open(self.r_location) as f: #use the "with open() as f:" idiom to ensure file gets closed when you're done with it
for line in f: #iterating over an open file defaults to line by line and we won't need line number with the nested loop approach
if re_beg_spl.match(line): #start a new record
tags = {} #container for element tags and values
case = '' #case number for this record
for line in f: #re-use iterator for inner loop so lines are consumed (outer loop will pick up where inner loop leaves off)
match_case = re_casenum.match(line)
match_elem = re_tag_val.match(line)
match_end = re_end_spl.match(line)
if match_case:
case = match_case.group(1) #are match groups 1 or 0 indexed? I didn't look it up..
elif match_elem:
tags[match_elem.group(1)] = match_elem.group(2)
elif match_end: #end of a record -- save info and break out of inner loop
caseinfo = {case: tags}
print(caseinfo)
self.records.append(caseinfo)
break
使用这种方法限制了对有效全局变量的需求(使用对象的属性来传递状态),这会在程序上强制执行更多结构(并使其更简单)。这也消除了您已经检查过的线路的重新循环,并多次重新读取文件(如果您有机械硬盘驱动器,这可能是您的速度限制因素)。我没有在结构中包含任何可能的中断检查(例如,缺少结束标记或id标记)但是它们可以以相当简单的方式添加。