파이썬을 사용하여 XML을 JSON으로 변환 하시겠습니까?


170

웹에서 부적절한 XML-> JSON 코드가 상당히 많이 보이며 Stack 사용자와 약간의 상호 작용을 하면서이 군중이 Google 결과의 처음 몇 페이지 이상을 도울 수 있다고 확신합니다.

따라서 날씨 피드를 파싱하고 있으며 수많은 웹 사이트에서 날씨 위젯을 채워야합니다. 우리는 지금 파이썬 기반 솔루션을 찾고 있습니다.

이 공개 weather.com RSS 피드 는 우리가 분석 할 내용의 좋은 예입니다 ( 실제 weather.com 피드에는 파트너 관계로 인해 추가 정보가 포함되어 있습니다 ).

간단히 말해서 파이썬을 사용하여 XML을 JSON으로 어떻게 변환해야합니까?

답변:


61

XML과 JSON간에 "일대일"매핑이 없으므로 하나를 다른 것으로 변환하려면 결과 로 수행 하려는 작업을 이해해야 합니다.

파이썬의 표준 라이브러리에는 XML (DOM, SAX 및 ElementTree 포함) 을 파싱하기위한 여러 모듈이 있습니다. Python 2.6부터 Python 데이터 구조를 JSON으로 또는 JSON으로 변환하는 기능이 json모듈에 포함되어 있습니다.

인프라가 있습니다.


2
xmljson IMHO는 다양한 컨벤션을 기본적으로 지원하여 사용하는 것이 가장 빠릅니다. pypi.org/project/xmljson
nitinr708

새로운 답변에서 이미 언급되었습니다. 여전히 유효한 XML 구조의 작은 하위 집합 만 다루지 만 사람들이 실제로 사용하는 것의 대부분을 설명합니다.
Dan Lenski

281

xmltodict (전체 공개 : 필자가 작성)는이 "standard"에 따라 XML을 dict + list + string 구조로 변환하는 데 도움이 됩니다. 그것은이다 국외 거주자는 그래서 매우 빨리 메모리에 전체 XML 트리를로드 할 필요가 없습니다, 기반.

해당 데이터 구조가 있으면 JSON으로 직렬화 할 수 있습니다.

import xmltodict, json

o = xmltodict.parse('<e> <a>text</a> <a>text</a> </e>')
json.dumps(o) # '{"e": {"a": ["text", "text"]}}'

@Martin Blech 내 django 모델 파일에서 json 파일을 만드는 경우. 필수 필드의 XML을 json으로 변환하기 위해 XML 파일을 어떻게 매핑합니까?
say

1
@sayth 나는 이것을 별도의 SO 질문으로 게시해야한다고 생각합니다.
마틴 블리치

@ 마틴 블레 치. 질문을 추가했지만 SO에 맞추기가 다소 어렵습니다. 초보자이므로 최대한 많은 정보를 제공했지만 더 명확한 정보가 필요할 것으로 예상됩니다. stackoverflow.com/q/23676973/461887
sayth

너무 오랜 시간이 지나면 xmltodict가 일부 Linux 배포판의 "표준"라이브러리가 아니라는 것에 약간 놀랐습니다. 우리가 읽을 수있는 직선에서 일을하는 것 같다 입력해도, 나는 불행하게도 XSLT 변환과 같은 다른 솔루션을 사용합니다
sancelot

이 환상적인 라이브러리를 작성해 주셔서 감사합니다. bs4XML을 사용하여
지시

24

xmljson 라이브러리를 사용하여 다른 XML JSON 규칙을 사용하여 변환 할 수 있습니다 .

예를 들어이 XML은 다음과 같습니다.

<p id="1">text</p>

BadgerFish 규칙 을 통해 다음과 같이 변환됩니다 .

{
  'p': {
    '@id': 1,
    '$': 'text'
  }
}

그리고 GData 규칙 을 통해 (속성은 지원되지 않습니다) :

{
  'p': {
    '$t': 'text'
  }
}

... 그리고 Parker 규칙 을 통해 (속성은 지원되지 않습니다) :

{
  'p': 'text'
}

동일한 규칙을 사용하여 XML에서 JSON으로, JSON에서 XML로 변환 할 수 있습니다.

>>> import json, xmljson
>>> from lxml.etree import fromstring, tostring
>>> xml = fromstring('<p id="1">text</p>')
>>> json.dumps(xmljson.badgerfish.data(xml))
'{"p": {"@id": 1, "$": "text"}}'
>>> xmljson.parker.etree({'ul': {'li': [1, 2]}})
# Creates [<ul><li>1</li><li>2</li></ul>]

공개 : 나는이 도서관을 썼다. 미래의 검색 자들에게 도움이되기를 바랍니다.


4
그것은 꽤 멋진 도서관이지만 개인 오픈 소스 라이브러리를 제공하는 방법을 읽으십시오 . 더 많은 답변을 게시하기 전에.
Martijn Pieters

1
감사합니다 @MartijnPieters-방금이 과정을 거쳤으며이를 고수하겠습니다.
S Anand

1
솔루션에 대한 감사 Anand – 잘 작동하는 것 같고 외부 종속성이 없으며 다른 규칙을 사용하여 속성을 처리하는 방법에 많은 유연성을 제공합니다. 정확히 내가 필요한 것은 내가 찾은 가장 유연하고 간단한 솔루션이었습니다.
mbbeme

감사합니다 Anand-불행히도, utf8 인코딩으로 XML을 구문 분석 할 수는 없습니다. 소스를 통해 XMLParser (..)를 통해 인코딩 세트가 무시되는 것 같습니다
Patrik Beck

@PatrikBeck XML의 작은 예제를 utf8 인코딩으로 나누면 좋을까요?
S Anand

11

언젠가 모든 데이터 대신 응답 코드 만 얻는다면 json 구문 분석과 같은 오류가 발생 하므로 텍스트 로 변환해야 합니다

import xmltodict

data = requests.get(url)
xpars = xmltodict.parse(data.text)
json = json.dumps(xpars)
print json 

7

여기에 내가 작성한 코드가 있습니다. 내용을 파싱하지 않고 평범한 변환 만하면됩니다.

from xml.dom import minidom
import simplejson as json
def parse_element(element):
    dict_data = dict()
    if element.nodeType == element.TEXT_NODE:
        dict_data['data'] = element.data
    if element.nodeType not in [element.TEXT_NODE, element.DOCUMENT_NODE, 
                                element.DOCUMENT_TYPE_NODE]:
        for item in element.attributes.items():
            dict_data[item[0]] = item[1]
    if element.nodeType not in [element.TEXT_NODE, element.DOCUMENT_TYPE_NODE]:
        for child in element.childNodes:
            child_name, child_dict = parse_element(child)
            if child_name in dict_data:
                try:
                    dict_data[child_name].append(child_dict)
                except AttributeError:
                    dict_data[child_name] = [dict_data[child_name], child_dict]
            else:
                dict_data[child_name] = child_dict 
    return element.nodeName, dict_data

if __name__ == '__main__':
    dom = minidom.parse('data.xml')
    f = open('data.json', 'w')
    f.write(json.dumps(parse_element(dom), sort_keys=True, indent=4))
    f.close()

7

XML 기반 마크 업을 JSON으로 전송하여 손실없이 원래 형식으로 다시 변환 할 수있는 방법이 있습니다. http://jsonml.org/를 참조하십시오 .

일종의 XSLT JSON입니다. 도움이 되었기를 바랍니다.


7

여전히 이것이 필요할 수있는 사람에게. 이 변환을 수행하는 새롭고 간단한 코드가 있습니다.

from xml.etree import ElementTree as ET

xml    = ET.parse('FILE_NAME.xml')
parsed = parseXmlToJson(xml)


def parseXmlToJson(xml):
  response = {}

  for child in list(xml):
    if len(list(child)) > 0:
      response[child.tag] = parseXmlToJson(child)
    else:
      response[child.tag] = child.text or ''

    # one-liner equivalent
    # response[child.tag] = parseXmlToJson(child) if len(list(child)) > 0 else child.text or ''

  return response

1
불행히도 특정 값이 xml에 있으면 키 3.7에 예기치 않은 데이터를 추가합니다. 예를 들어 루트 레벨 노드의 xmlns 태그는 모든 노드 키에 다음과 같이 표시됩니다. { '{ maven .apache.org / POM / 4.0.0 } artifactId ':'test-service '는 다음과 같이 xml에서 제공됩니다. <project xmlns = " maven.apache.org/POM/4.0.0"xsi : schemaLocation = " maven .apache.org / POM / 4.0.0 maven.apache.org/xsd/maven-4.0.0.xsd "xmlns : xsi =" w3.org/2001/XMLSchema-instance "> <modelVersion> 4.0.0 </ modelVersion>
hrbdg

5

http://designtheory.org/library/extrep/designdb-1.0.pdf참조하십시오 . 이 프로젝트는 큰 XML 파일 라이브러리의 XML을 JSON으로 변환하는 것으로 시작합니다. 변환에 대한 많은 연구가 있었고 가장 간단한 직관적 인 XML-> JSON 매핑이 생성되었습니다 (문서의 초기에 설명되어 있음). 요약하면 모든 것을 JSON 객체로 변환하고 반복 블록을 객체 목록으로 넣습니다.

키 / 값 쌍을 의미하는 객체 (Python의 사전, Java의 해시 맵, JavaScript의 객체)

동일한 문서를 얻기 위해 XML로 다시 매핑 할 수는 없습니다. 그 이유는 키 / 값 쌍이 속성인지 또는 <key>value</key> 정보 때문에 정보가 손실됩니다.

나에게 묻는다면, 속성은 시작하기위한 핵이다. 그런 다음 다시 HTML에서 잘 작동했습니다.


4

글쎄, 아마도 가장 간단한 방법은 XML을 사전으로 구문 분석 한 다음 simplejson으로 직렬화하는 것입니다.


4

직접 전환하지 않는 것이 좋습니다. XML을 객체로 변환 한 다음 객체에서 JSON으로 변환합니다.

내 생각에 이것은 XML과 JSON이 어떻게 대응되는지에 대한 명확한 정의를 제공합니다.

제대로 되려면 시간이 걸리고 일부를 생성하는 데 도움이되는 도구를 작성할 수도 있지만 대략 다음과 같습니다.

class Channel:
  def __init__(self)
    self.items = []
    self.title = ""

  def from_xml( self, xml_node ):
    self.title = xml_node.xpath("title/text()")[0]
    for x in xml_node.xpath("item"):
      item = Item()
      item.from_xml( x )
      self.items.append( item )

  def to_json( self ):
    retval = {}
    retval['title'] = title
    retval['items'] = []
    for x in items:
      retval.append( x.to_json() )
    return retval

class Item:
  def __init__(self):
    ...

  def from_xml( self, xml_node ):
    ...

  def to_json( self ):
    ...

2

간단한 XML 스니핑에서 정규 표현식을 사용하면 문제를 해결할 수 있습니다. 예를 들면 다음과 같습니다.

# <user><name>Happy Man</name>...</user>
import re
names = re.findall(r'<name>(\w+)<\/name>', xml_string)
# do some thing to names

@Dan이 말했듯이 XML 파싱으로 수행하려면 데이터가 다르기 때문에 일대일 솔루션이 없습니다. 내 제안은 lxml을 사용하는 것입니다. json으로 끝나지 않았지만 lxml.objectify 는 조용한 결과를 제공합니다.

>>> from lxml import objectify
>>> root = objectify.fromstring("""
... <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...   <a attr1="foo" attr2="bar">1</a>
...   <a>1.2</a>
...   <b>1</b>
...   <b>true</b>
...   <c>what?</c>
...   <d xsi:nil="true"/>
... </root>
... """)

>>> print(str(root))
root = None [ObjectifiedElement]
    a = 1 [IntElement]
      * attr1 = 'foo'
      * attr2 = 'bar'
    a = 1.2 [FloatElement]
    b = 1 [IntElement]
    b = True [BoolElement]
    c = 'what?' [StringElement]
    d = None [NoneElement]
      * xsi:nil = 'true'

1
그러나 중복 노드를 제거합니다
Pooya

2

XML 파싱을위한 내장 라이브러리는 꽤 좋지만 lxml에 부분적입니다. 입니다.

그러나 RSS 피드 를 파싱하려면 Atom을 파싱 할 수있는 Universal Feed Parser를 권장 합니다. 주요 이점은 대부분의 기형 사료를 소화 할 수 있다는 것입니다.

Python 2.6에는 이미 JSON 파서가 포함되어 있지만 속도향상된 최신 버전을 simplejson 으로 사용할 수 있습니다 .

이러한 도구를 사용하면 앱을 만드는 것이 그렇게 어렵지 않아야합니다.


2

내 대답 주소를 특정 (다소 공통)의 경우는 정말 전체 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_") 합니다.

이 부분을 벤치마킹하지 않았습니다.


내가 뭘하려고하면 json.dumps(tree)그것은 말한다 유형 'ETreeDictWrapper'의 개체 JSON의 직렬화 할 수없는
블라드 T.

2

파이썬에서 XML로 무엇이든 할 때는 거의 항상 lxml 패키지를 사용합니다. 나는 대부분의 사람들이 lxml을 사용한다고 생각합니다. xmltodict를 사용할 수는 있지만 XML 구문 분석에 대한 페널티를 다시 지불해야합니다.

lxml을 사용하여 XML을 json으로 변환하려면 다음을 수행하십시오.

  1. lxml을 사용하여 XML 문서 구문 분석
  2. lxml을 dict로 변환
  3. 목록을 json으로 변환

내 프로젝트에서 다음 클래스를 사용합니다. toJson 방법을 사용하십시오.

from lxml import etree 
import json


class Element:
    '''
    Wrapper on the etree.Element class.  Extends functionality to output element
    as a dictionary.
    '''

    def __init__(self, element):
        '''
        :param: element a normal etree.Element instance
        '''
        self.element = element

    def toDict(self):
        '''
        Returns the element as a dictionary.  This includes all child elements.
        '''
        rval = {
            self.element.tag: {
                'attributes': dict(self.element.items()),
            },
        }
        for child in self.element:
            rval[self.element.tag].update(Element(child).toDict())
        return rval


class XmlDocument:
    '''
    Wraps lxml to provide:
        - cleaner access to some common lxml.etree functions
        - converter from XML to dict
        - converter from XML to json
    '''
    def __init__(self, xml = '<empty/>', filename=None):
        '''
        There are two ways to initialize the XmlDocument contents:
            - String
            - File

        You don't have to initialize the XmlDocument during instantiation
        though.  You can do it later with the 'set' method.  If you choose to
        initialize later XmlDocument will be initialized with "<empty/>".

        :param: xml Set this argument if you want to parse from a string.
        :param: filename Set this argument if you want to parse from a file.
        '''
        self.set(xml, filename) 

    def set(self, xml=None, filename=None):
        '''
        Use this to set or reset the contents of the XmlDocument.

        :param: xml Set this argument if you want to parse from a string.
        :param: filename Set this argument if you want to parse from a file.
        '''
        if filename is not None:
            self.tree = etree.parse(filename)
            self.root = self.tree.getroot()
        else:
            self.root = etree.fromstring(xml)
            self.tree = etree.ElementTree(self.root)


    def dump(self):
        etree.dump(self.root)

    def getXml(self):
        '''
        return document as a string
        '''
        return etree.tostring(self.root)

    def xpath(self, xpath):
        '''
        Return elements that match the given xpath.

        :param: xpath
        '''
        return self.tree.xpath(xpath);

    def nodes(self):
        '''
        Return all elements
        '''
        return self.root.iter('*')

    def toDict(self):
        '''
        Convert to a python dictionary
        '''
        return Element(self.root).toDict()

    def toJson(self, indent=None):
        '''
        Convert to JSON
        '''
        return json.dumps(self.toDict(), indent=indent)


if __name__ == "__main__":
    xml='''<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>
'''
    doc = XmlDocument(xml)
    print doc.toJson(indent=4)

내장 메인 의 출력 은 다음과 같습니다.

{
    "system": {
        "attributes": {}, 
        "product": {
            "attributes": {}, 
            "demod": {
                "attributes": {}, 
                "frequency": {
                    "attributes": {
                        "units": "MHz", 
                        "value": "2.215"
                    }, 
                    "blah": {
                        "attributes": {
                            "value": "1"
                        }
                    }
                }
            }
        }
    }
}

이 XML의 변형은 다음과 같습니다.

<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>




1

declxml을 사용할 수 있습니다. 다중 속성 및 복잡한 중첩 지원과 같은 고급 기능이 있습니다. 간단한 프로세서 만 작성하면됩니다. 또한 동일한 코드를 사용하여 JSON으로 다시 변환 할 수도 있습니다. 그것은 매우 간단하고 문서는 훌륭합니다.

링크 : https://declxml.readthedocs.io/en/latest/index.html


-1

Python 에서 데이터 준비 : JSON 을 만들려면 먼저 를 준비해야합니다. 파이썬에서 List와 Dictionary를 사용하여 데이터를 준비 할 수 있습니다.

파이썬 리스트 <==> JSON 배열

Python Dictionary <==> JSON Object (Key Value Format) 자세한 내용은 이것을 확인하십시오.

https://devstudioonline.com/article/create-json-and-xml-in-python


스택 오버플로에 오신 것을 환영합니다! 링크는 지식을 공유하는 좋은 방법이지만, 나중에 링크가 끊어지면 질문에 대답하지 않습니다. 질문에 답변하는 링크의 필수 내용을 답변에 추가하십시오. 내용이 너무 복잡하거나 여기에 맞지 않을 경우 제안 된 솔루션의 일반적인 개념을 설명하십시오. 항상 원래 솔루션의 웹 사이트에 대한 링크 참조를 유지해야합니다. 참조 : 좋은 답변을 작성하려면 어떻게합니까?
sɐunıɔ ןɐ qɐp

-4

JSON 형식으로 데이터를 나타내려면

name=John
age=20
gender=male
address=Sector 12 Greater Kailash, New Delhi
Jobs=Noida,Developer | Gurugram,Tester |Faridabad,Designer

에서 JSON 우리는 키와 값 형식의 데이터를 repesent

{
    "name":"john",
    "age":20,
    "gender":"male",
    "address":["New kP college","Greater Kailash","New Delhi"],
    "jobs":[
               {"Place":"Noida","Title":"Developer "},
               {"Place":"Gurugram","Title":"Tester "},
               {"Place":"Faridabad","Title":"Designer"}
           ]
}

XML 형식으로 데이터를 나타내려면

<!-- In xml we write a code under a key you can take any key -->
<info> <!-- key open -->

<name> john </name> 
<age> 20 </age>
<gender> male </gender>

<address> 
<item> New kP college </item>
<item> Greater Kailash </item>
<item> New Delhi </item>
</address>

<jobs>
 <item>
  <title>Developer </title>
  <place>Noida</place>
 </item>

 <item>
  <title>Designer</title>
  <place>Gurugram</place>
 </item>
 
 <item>
  <title>Developer </title>
  <place>Faridabad</place>
 </item>
</jobs>

</info> <!-- key close-->

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.