Python이 XML을 구문 분석하는 여러 가지 방법을 분석합니다.

巴扎黑
풀어 주다: 2017-09-19 10:20:27
원래의
2544명이 탐색했습니다.

처음 PYTHON을 배웠을 때는 DOM과 SAX라는 두 가지 파싱 방법만 알고 있었는데, 처리해야 하는 파일의 양이 많아 효율성이 이상적이지는 않았습니다. 받아들일 수 없다.

인터넷에서 검색해보니 현재 널리 사용되고 상대적으로 효율적인 ElementTree도 많은 사람들이 추천하는 알고리즘이어서 실제 측정과 비교에 이 알고리즘을 사용했는데, 하나는 일반적인 ElementTree(ET) 중 하나는 ElementTree.iterparse(ET_iter)입니다.

이 기사에서는 DOM, SAX, ET, ET_iter의 네 가지 방법을 수평적으로 비교하고, 동일한 파일을 처리하는 데 걸리는 시간을 비교하여 각 알고리즘의 효율성을 평가합니다.

네 가지 파싱 방법은 프로그램에 함수로 작성되고 메인 프로그램에서 별도로 호출되어 파싱 효율성을 평가합니다.

압축 해제된 XML 파일 내용 예:

Python이 XML을 구문 분석하는 여러 가지 방법을 분석합니다.

주 프로그램 함수 호출 부분 코드:

  print("文件计数:%d/%d." % (gz_cnt,paser_num))
  str_s,cnt = dom_parser(gz)
  #str_s,cnt = sax_parser(gz)
  #str_s,cnt = ET_parser(gz)
  #str_s,cnt = ET_parser_iter(gz)
  output.write(str_s)
  vs_cnt += cnt
로그인 후 복사

초기 함수 호출에서 함수는 두 개의 값을 반환하지만 함수 호출 값을 수신하면 두 개의 변수가 각 함수가 두 번 실행되는 호출은 나중에 두 개의 변수를 한 번에 호출하여 반환 값을 받도록 수정되어 잘못된 호출을 줄였습니다.

1. DOM 구문 분석

함수 정의 코드:

def dom_parser(gz):
  import gzip,cStringIO
  import xml.dom.minidom
  
  vs_cnt = 0
  str_s = ''
  file_io = cStringIO.StringIO()
  xm = gzip.open(gz,'rb')
  print("已读入:%s.\n解析中:" % (os.path.abspath(gz)))
  doc = xml.dom.minidom.parseString(xm.read())
  bulkPmMrDataFile = doc.documentElement
  #读入子元素
  enbs = bulkPmMrDataFile.getElementsByTagName("eNB")
  measurements = enbs[0].getElementsByTagName("measurement")
  objects = measurements[0].getElementsByTagName("object")
  #写入csv文件
  for object in objects:
    vs = object.getElementsByTagName("v")
    vs_cnt += len(vs)
    for v in vs:
      file_io.write(enbs[0].getAttribute("id")+' '+object.getAttribute("id")+' '+\
      object.getAttribute("MmeUeS1apId")+' '+object.getAttribute("MmeGroupId")+' '+object.getAttribute("MmeCode")+' '+\
      object.getAttribute("TimeStamp")+' '+v.childNodes[0].data+'\n') #获取文本值
  str_s = (((file_io.getvalue().replace(' \n','\r\n')).replace(' ',',')).replace('T',' ')).replace('NIL','')
  xm.close()
  file_io.close()
  return (str_s,vs_cnt)
로그인 후 복사

프로그램 실행 결과:

**************************** ******* *********************

프로그램 처리가 시작됩니다.

입력 디렉터리는 /tmcdata/mro2csv/input31/입니다.

출력 디렉터리는 /tmcdata/mro2csv/output31/입니다.

입력 디렉터리의 .gz 파일 수는 12개이며, 이번에는 그 중 12개가 처리됩니다.

**************************************************** **

파일 수: 1/12.

읽기: /tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_234598_20160224060000.xml.gz.

파싱:

파일 수: 2/12.

입력 읽기: / tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_233798_20160224060000.xml.gz.

분석:

파일 수: 3/12.

읽기: /tmcdata/mro2csv/input31/TD -LTE_MRO _NSN_OMC_123798_20160224060000.xml.gz.

구문 분석 :

…………………………………………

파일 수: 12/12.

읽기: /tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_235598_20160224060000. gz.

파싱:

VS 행 수: 177849, 실행 시간: 107.077867, 초당 처리되는 행: 1660.

작성 대상: /tmcdata/mro2csv/output31/mro_0001.csv.

**************************************************** **

프로그램 처리가 종료됩니다.

DOM 파싱은 파일 전체를 메모리로 읽어와 트리 구조를 구축해야 하기 때문에 메모리 소모량과 시간 소모량이 상대적으로 높지만, 로직이 단순하고 콜백 함수를 정의할 필요가 없다는 장점이 있습니다. 구현하기 쉽습니다.

2.SAX 구문 분석

함수 정의 코드:

def sax_parser(gz):
  import os,gzip,cStringIO
  from xml.parsers.expat import ParserCreate
  #变量声明
  d_eNB = {}
  d_obj = {}
  s = ''
  global flag 
  flag = False
  file_io = cStringIO.StringIO()
  
  #Sax解析类
  class DefaultSaxHandler(object):
    #处理开始标签
    def start_element(self, name, attrs):
      global d_eNB
      global d_obj
      global vs_cnt
      if name == 'eNB':
        d_eNB = attrs
      elif name == 'object':
        d_obj = attrs
      elif name == 'v':
        file_io.write(d_eNB['id']+' '+ d_obj['id']+' '+d_obj['MmeUeS1apId']+' '+d_obj['MmeGroupId']+' '+d_obj['MmeCode']+' '+d_obj['TimeStamp']+' ')
        vs_cnt += 1
      else:
        pass
    #处理中间文本
    def char_data(self, text):
      global d_eNB
      global d_obj
      global flag
      if text[0:1].isnumeric():
        file_io.write(text)
      elif text[0:17] == 'MR.LteScPlrULQci1':
        flag = True
        #print(text,flag)
      else:
        pass
    #处理结束标签
    def end_element(self, name):
      global d_eNB
      global d_obj
      if name == 'v':
        file_io.write('\n')
      else:
        pass
  
  #Sax解析调用
  handler = DefaultSaxHandler()
  parser = ParserCreate()
  parser.StartElementHandler = handler.start_element
  parser.EndElementHandler = handler.end_element
  parser.CharacterDataHandler = handler.char_data
  vs_cnt = 0
  str_s = ''
  xm = gzip.open(gz,'rb')
  print("已读入:%s.\n解析中:" % (os.path.abspath(gz)))
  for line in xm.readlines():
    parser.Parse(line) #解析xml文件内容
    if flag:
      break
  str_s = file_io.getvalue().replace(' \n','\r\n').replace(' ',',').replace('T',' ').replace('NIL','')  #写入解析后内容
  xm.close()
  file_io.close()
  return (str_s,vs_cnt)
로그인 후 복사

프로그램 실행 결과:

******************************** ******* *********************

프로그램 처리가 시작됩니다.

입력 디렉터리는 /tmcdata/mro2csv/input31/입니다.

출력 디렉터리는 /tmcdata/mro2csv/output31/입니다.

입력 디렉터리의 .gz 파일 수는 12개이며, 이번에는 그 중 12개가 처리됩니다.

**************************************************** **

파일 수: 1/12.

읽기: /tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_234598_20160224060000.xml.gz.

파싱:

파일 수: 2/12.

입력 읽기: / tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_233798_20160224060000.xml.gz.

분석:

파일 수: 3/12.

읽기: /tmcdata/mro2csv/input31/TD -LTE_MRO _NSN_OMC_123798_20160224060000.xml.gz.

구문 분석 :

...................................................

파일 개수: 12/12.

읽기: /tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_235598_20160224060000.xml.gz.

파싱:

VS 행 개수: 177849 , 실행 시간 :14.386779, 초당 숫자 처리된 행 수: 12361.

작성 대상: /tmcdata/mro2csv/output31/mro_0001.csv.

**************************************************** **

프로그램 처리가 종료됩니다.

SAX 구문 분석은 DOM 구문 분석보다 실행 시간이 훨씬 짧습니다. SAX는 라인별 구문 분석을 사용하므로 대용량 파일을 처리하는 데 메모리를 덜 차지합니다. 따라서 SAX 구문 분석은 현재 널리 사용되는 구문 분석 방법입니다. 단점은 콜백 함수를 직접 구현해야 하고 로직이 상대적으로 복잡하다는 점입니다.

3. ET 분석

함수 정의 코드:

def ET_parser(gz):
  import os,gzip,cStringIO
  import xml.etree.cElementTree as ET
  vs_cnt = 0
  str_s = ''
  file_io = cStringIO.StringIO()
  xm = gzip.open(gz,'rb')
  print("已读入:%s.\n解析中:" % (os.path.abspath(gz)))
  tree = ET.ElementTree(file=xm)
  root = tree.getroot()
  for elem in root[1][0].findall('object'):
      for v in elem.findall('v'):
          file_io.write(root[1].attrib['id']+' '+elem.attrib['TimeStamp']+' '+elem.attrib['MmeCode']+' '+\
          elem.attrib['id']+' '+ elem.attrib['MmeUeS1apId']+' '+ elem.attrib['MmeGroupId']+' '+ v.text+'\n')
      vs_cnt += 1
  str_s = file_io.getvalue().replace(' \n','\r\n').replace(' ',',').replace('T',' ').replace('NIL','')  #写入解析后内容
  xm.close()
  file_io.close()
  return (str_s,vs_cnt)
로그인 후 복사

프로그램 실행 결과:

******************************** * *********************

프로그램 처리가 시작됩니다.

입력 디렉터리는 /tmcdata/mro2csv/input31/입니다.

출력 디렉터리는 /tmcdata/mro2csv/output31/입니다.

입력 디렉터리의 .gz 파일 수는 12개이며, 이번에는 그 중 12개가 처리됩니다.

**************************************************** **

파일 수: 1/12.

읽기: /tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_234598_20160224060000.xml.gz.

파싱:

파일 수: 2/12.

입력 읽기: / tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_233798_20160224060000.xml.gz.

분석:

파일 수: 3/12.

읽기: /tmcdata/mro2csv/input31/TD -LTE_MRO _NSN_OMC_123798_20160224060000.xml.gz.

구문 분석 :

...........................................

文件计数:12/12.

已读入:/tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_235598_20160224060000.xml.gz.

解析中:

VS行计数:177849,运行时间:4.308103,每秒处理行数:41282。

已写入:/tmcdata/mro2csv/output31/mro_0001.csv。

**************************************************

程序处理结束。

相较于SAX解析,ET解析时间更短,并且函数实现也比较简单,所以ET具有类似DOM的简单逻辑实现且匹敌SAX的解析效率,因此ET是目前XML解析的首选。

4、ET_iter解析

函数定义代码:

def ET_parser_iter(gz):
  import os,gzip,cStringIO
  import xml.etree.cElementTree as ET
  vs_cnt = 0
  str_s = ''
  file_io = cStringIO.StringIO()
  xm = gzip.open(gz,'rb')
  print("已读入:%s.\n解析中:" % (os.path.abspath(gz)))
  d_eNB = {}
  d_obj = {}
  i = 0
  for event,elem in ET.iterparse(xm,events=('start','end')):
    if i >= 2:
      break    
    elif event == 'start':
          if elem.tag == 'eNB':
              d_eNB = elem.attrib
          elif elem.tag == 'object':
        d_obj = elem.attrib
      elif event == 'end' and elem.tag == 'smr':
      i += 1
    elif event == 'end' and elem.tag == 'v':
      file_io.write(d_eNB['id']+' '+d_obj['TimeStamp']+' '+d_obj['MmeCode']+' '+d_obj['id']+' '+\
      d_obj['MmeUeS1apId']+' '+ d_obj['MmeGroupId']+' '+str(elem.text)+'\n')
          vs_cnt += 1
      elem.clear()
  str_s = file_io.getvalue().replace(' \n','\r\n').replace(' ',',').replace('T',' ').replace('NIL','')  #写入解析后内容
  xm.close()
  file_io.close()
  return (str_s,vs_cnt)
로그인 후 복사

程序运行结果:

**************************************************

程序处理启动。

输入目录为:/tmcdata/mro2csv/input31/。

输出目录为:/tmcdata/mro2csv/output31/。

输入目录下.gz文件个数为:12,本次处理其中的12个。

**************************************************

文件计数:1/12.

已读入:/tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_234598_20160224060000.xml.gz.

解析中:

文件计数:2/12.

已读入:/tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_233798_20160224060000.xml.gz.

解析中:

文件计数:3/12.

已读入:/tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_123798_20160224060000.xml.gz.

解析中:

...................................................

文件计数:12/12.

已读入:/tmcdata/mro2csv/input31/TD-LTE_MRO_NSN_OMC_235598_20160224060000.xml.gz.

解析中:

VS行计数:177849,运行时间:3.043805,每秒处理行数:58429。

已写入:/tmcdata/mro2csv/output31/mro_0001.csv。

**************************************************

程序处理结束。

在引入了ET_iter解析后,解析效率比ET提升了近50%,而相较于DOM解析更是提升了35倍,在解析效率提升的同时,由于其采用了iterparse这个循序解析的工具,其内存占用也是比较小的。

위 내용은 Python이 XML을 구문 분석하는 여러 가지 방법을 분석합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!