web-dev-qa-db-ja.com

Pythonを使用してXMLをJSONに変換しますか?

私はWebでXML-> JSONコードのかなりの部分をかなり見ましたが、Stackのユーザーと少し対話したことがあるので、この群衆はGoogleの結果の最初の数ページよりも多くのことを助けることができると確信しています。

そのため、天気フィードを解析し、多数のWebサイトに天気ウィジェットを追加する必要があります。現在、Pythonベースのソリューションを検討しています。

この公開 weather.com RSSフィード は、解析対象の良い例です(実際のweather.comフィードには、w/themとのパートナーシップのために追加情報が含まれています)。

簡単に言えば、Pythonを使用してXMLをJSONに変換する方法を教えてください。

150
Pete Karl II

XMLとJSONの間に「1対1」のマッピングはないため、一方を他方に変換するには、何をしたいかをある程度理解する必要がありますdo結果で。

そうは言っても、Pythonの標準ライブラリには XMLを解析するためのいくつかのモジュール (DOM、SAX、ElementTreeを含む)があります。 Python 2.6では、Pythonデータ構造とJSONの変換のサポートが jsonモジュール に含まれています。

インフラストラクチャはそこにあります。

56
Dan Lenski

xmltodict (完全開示:私が書いた)は、XMLをdict + list + string構造に変換するのに役立ちます。これは "standard" に従います。 Expat -basedなので、非常に高速であり、XMLツリー全体をメモリにロードする必要はありません。

そのデータ構造を取得したら、それをJSONにシリアル化できます。

import xmltodict, json

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

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>]

開示:このライブラリを書きました。それが将来の検索者に役立つことを願っています。

19
S Anand

XMLベースのマークアップをJSONとして転送する方法があります。これにより、元の形式にロスレスで変換できます。 http://jsonml.org/ を参照してください。

JSONの一種のXSLTです。お役に立てば幸いです

7
themihai

そのために私が作成したコードを次に示します。内容の解析はなく、単なる変換です。

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 __== '__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
Paulo Vj

すべてのデータではなく応答コードのみを取得する場合、json parseのようなエラーが存在するため、textとして変換する必要があります

import xmltodict

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

http://designtheory.org/library/extrep/designdb-1.0.pdf をご覧ください。このプロジェクトは、XMLファイルの大規模なライブラリのXMLからJSONへの変換から始まります。変換では多くの研究が行われ、最も単純で直感的なXML-> JSONマッピングが作成されました(ドキュメントの初期段階で説明されています)。要約すると、すべてをJSONオブジェクトに変換し、繰り返しブロックをオブジェクトのリストとして配置します。

キー/値ペアを意味するオブジェクト(Pythonの辞書、Javaのハッシュマップ、JavaScriptのオブジェクト)

同じドキュメントを取得するためのXMLへのマッピングはありません。その理由は、キー/値のペアが属性であるか<key>value</key>であるかが不明であるため、その情報が失われるためです。

あなたが私に尋ねると、属性は開始するハックです。その後、再びHTMLでうまく機能しました。

5
pykler

おそらく、おそらく最も簡単な方法は、XMLを辞書に解析し、それをsimplejsonでシリアル化することです。

4
dguaraglia

直接のコンバージョンには進まないことをお勧めします。 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 ):
    ...
4

まだこれが必要な人には。この変換を行うための新しい、シンプルなコードを次に示します。

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
2
jnhustin

単純な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'
2
Andrew_1510

XML解析用の組み込みライブラリは非常に優れていますが、私は lxml の一部です。

しかし、RSSフィードの解析には niversal Feed Parser をお勧めします。これはAtomも解析できます。その主な利点は、ほとんどの不正なフィードでも消化できることです。

Python 2.6にはすでにJSONパーサーが含まれていますが、新しい 速度が改善されたバージョンsimplejson として利用可能です。

これらのツールを使用してアプリを作成するのはそれほど難しくありません。

2
Luka Marinko

pythonでXMLを使用して何かをするときは、ほとんど常にlxmlパッケージを使用します。ほとんどの人がlxmlを使用していると思います。 xmltodictを使用することもできますが、XMLを再度解析するというペナルティを支払う必要があります。

LxmlでXMLをjsonに変換するには:

  1. Lxmlを使用してXMLドキュメントを解析する
  2. Lxmlを辞書に変換する
  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 __== "__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)

組み込みのmainからの出力は次のとおりです。

{
    "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>
2
shrewmouse

ここにあるものは積極的に維持されており、これまでのところ私のお気に入りです: xml2json in python

1
typelogic

Declxmlを使用できます。マルチ属性や複雑なネストサポートなどの高度な機能があります。単純なプロセッサを作成するだけです。また、同じコードを使用して、JSONに戻すこともできます。それはかなり簡単で、ドキュメントは素晴らしいです。

リンク: https://declxml.readthedocs.io/en/latest/index.html

1
srth12

lxml2jsonをチェックしてください(開示:書きました)

https://github.com/rparelius/lxml2json

非常に高速で軽量(lxmlのみが必要)であり、1つの利点は、特定の要素をリストまたは辞書に変換するかどうかを制御できることです。

1
Robert Parelius

jsonpickle またはfeedparserを使用している場合は、試すことができます feed_pa​​rser_to_json.py

1
choonkeat

私の答えは、xml全体をjsonに実際に変換する必要はない特定の(やや一般的な)ケースに対応していますが、必要なのはxmlの特定の部分をトラバース/アクセスすることです、fastおよびsimple(json/dictのような操作を使用)である必要があります。

アプローチ

このため、lxmlを使用してXMLをetreeに解析することは非常に高速であることに注意することが重要です。他のほとんどの答えの遅い部分は2番目のパスです。etree構造を(通常はpython-landで)走査し、jsonに変換します。

これは、この場合に私が最も見つけたアプローチにつながります:lxmlを使用してxmlを解析し、etreeノードを(怠lazに)ラップし、dictのようなインターフェースを提供します。

コード

コードは次のとおりです。

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を使用した場合と比較して、驚異的なstrikingの70倍(!)xmltodict そして、dictを直接走査します。

ボーナス

おまけに、構造はすでにdictに似ているため、xml2jsonの別の代替実装を無料で入手できます。 dict-like構造体をjson.dumpsに渡すだけです。何かのようなもの:

def xml_to_json(xmlstr, **kwargs):
    x = xml_to_dictlike(xmlstr, **kwargs)
    return json.dumps(x)

Xmlに属性が含まれる場合、キーが有効なjsonキーであることを確認するために、英数字attr_prefix(例:「ATTR_」)を使用する必要があります。

この部分のベンチマークは行っていません。

1
shx2

Python でデータを準備する JSON を作成するには、まずpythonでデータを準備する必要があります。 Pythonのリストと辞書を使用して、データを準備できます。

Python リスト<==> JSON 配列

Python 辞書<==> JSON Object(Key Value Format)詳細はこちらをご覧ください

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

0
Anushree Anisha