내 대답 주소를 특정 (다소 공통)의 경우는 정말 전체 XML로 변환 할 필요가 없습니다 JSON으로,하지만 당신이 필요는 XML의 트래버스 / 액세스 특정 부품에, 당신은 그것을 할 필요가 신속 하고, 단순합니다 (json / dict-like 연산 사용).
접근하다
이를 위해 xml을 etree로 파싱하는 lxml
것은 매우 빠릅니다. 대부분의 다른 답변에서 느린 부분은 두 번째 단계입니다 .etree 구조를 통과 (일반적으로 python-land)하여 json으로 변환합니다.
이 경우 내가 가장 잘 찾은 접근 방식으로 연결됩니다 :을 사용하여 xml을 구문 분석 lxml
한 다음 etree 노드를 느리게 감싸서 dict-like 인터페이스를 제공합니다.
암호
코드는 다음과 같습니다.
from collections import Mapping
import lxml.etree
class ETreeDictWrapper(Mapping):
def __init__(self, elem, attr_prefix = '@', list_tags = ()):
self.elem = elem
self.attr_prefix = attr_prefix
self.list_tags = list_tags
def _wrap(self, e):
if isinstance(e, basestring):
return e
if len(e) == 0 and len(e.attrib) == 0:
return e.text
return type(self)(
e,
attr_prefix = self.attr_prefix,
list_tags = self.list_tags,
)
def __getitem__(self, key):
if key.startswith(self.attr_prefix):
return self.elem.attrib[key[len(self.attr_prefix):]]
else:
subelems = [ e for e in self.elem.iterchildren() if e.tag == key ]
if len(subelems) > 1 or key in self.list_tags:
return [ self._wrap(x) for x in subelems ]
elif len(subelems) == 1:
return self._wrap(subelems[0])
else:
raise KeyError(key)
def __iter__(self):
return iter(set( k.tag for k in self.elem) |
set( self.attr_prefix + k for k in self.elem.attrib ))
def __len__(self):
return len(self.elem) + len(self.elem.attrib)
# defining __contains__ is not necessary, but improves speed
def __contains__(self, key):
if key.startswith(self.attr_prefix):
return key[len(self.attr_prefix):] in self.elem.attrib
else:
return any( e.tag == key for e in self.elem.iterchildren() )
def xml_to_dictlike(xmlstr, attr_prefix = '@', list_tags = ()):
t = lxml.etree.fromstring(xmlstr)
return ETreeDictWrapper(
t,
attr_prefix = '@',
list_tags = set(list_tags),
)
이 구현은 완전하지 않습니다. 예를 들어, 요소에 텍스트와 속성이 모두 있거나 텍스트와 자식이 모두있는 경우를 명확하게 지원하지 않습니다 (작성할 때 필요하지 않았기 때문에 만). 그래도 그것을 개선하기 위해.
속도
XML의 특정 요소 만 처리 해야하는 특정 사용 사례 에서이 접근법은 @Martin Blech의 xmltodict 를 사용한 다음 dict을 직접 통과하는 것과 비교하여 놀랍고 놀라운 속도를 70 (!) 까지 높였습니다 .
보너스
보너스로, 우리의 구조는 이미 dict-like와 같으므로 다른 대안 xml2json
을 무료로 구현할 수 있습니다. dict-like 구조체를에 전달하면 json.dumps
됩니다. 다음과 같은 것 :
def xml_to_json(xmlstr, **kwargs):
x = xml_to_dictlike(xmlstr, **kwargs)
return json.dumps(x)
XML에 속성이 포함 된 경우 영숫자를 사용해야합니다. attr_prefix
키가 유효한 json 키가되도록 (예 : "ATTR_") 합니다.
이 부분을 벤치마킹하지 않았습니다.