আমার উত্তরটি সুনির্দিষ্ট (এবং কিছুটা সাধারণ) কে সম্বোধন করে যেখানে আপনাকে পুরো এক্সএমএলকে জসনতে রূপান্তর করতে হবে না , তবে আপনাকে যা প্রয়োজন তা হল এক্সএমএলের নির্দিষ্ট অংশগুলি অতিক্রম / অ্যাক্সেস করা এবং আপনার এটি দ্রুত হওয়া দরকার এবং সরল (জসন / ডিক্ট-এর মতো ক্রিয়াকলাপগুলি ব্যবহার করে)।
অভিগমন
এর জন্য, এটি লক্ষ্য করা গুরুত্বপূর্ণ যে এক্স্রি ব্যবহার করে একটি এক্সএমএল পার্স lxml
করা অতি দ্রুত is অন্যান্য উত্তরের বেশিরভাগ ধীর গতির অংশটি দ্বিতীয় পাস: এট্রি কাঠামোকে অনুসরণ করে (সাধারণত পাইথন-জমিতে), এটি জসনে রূপান্তর করে।
যা আমাকে এই ক্ষেত্রে সবচেয়ে ভালভাবে আবিষ্কার করার পদ্ধতির দিকে নিয়ে যায়: এক্সএমএল ব্যবহার করে পার্সিং lxml
, এবং তারপরে এট্রি নোডগুলি (অলসভাবে) মোড়ানো, তাদের ডিকের মতো ইন্টারফেস সরবরাহ করে।
কোড
কোডটি এখানে:
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),
)
এই প্রয়োগটি সম্পূর্ণ নয়, উদাহরণস্বরূপ, এটি এমন কোনও ক্ষেত্রে পরিষ্কারভাবে সাপোর্ট করে না যেখানে কোনও উপাদানের পাঠ্য এবং বৈশিষ্ট্য, বা পাঠ্য এবং শিশু উভয়ই থাকে (কেবল কারণ যখন এটি লেখার সময় আমার প্রয়োজন হয়নি ...) এটি সহজ হওয়া উচিত যদিও এটি উন্নতি করতে।
গতি
আমার নির্দিষ্ট ব্যবহারের ক্ষেত্রে, যেখানে আমার কেবলমাত্র এক্সএমএলের নির্দিষ্ট উপাদানগুলি প্রক্রিয়া করার প্রয়োজন ছিল, এই পদ্ধতিটি @ মার্টিন ব্লচের এক্সএমল্টডিক্ট ব্যবহার করার এবং তারপরে ডিককে সরাসরি অনুসরণ করার তুলনায় (০ (!) ফ্যাক্টর দ্বারা একটি আশ্চর্যজনক এবং আকর্ষণীয় স্পিডআপ দিয়েছে ।
বোনাস
বোনাস হিসাবে, যেহেতু আমাদের কাঠামো ইতিমধ্যে ডিক্ট-এর মতো, তাই আমরা xml2json
নিখরচায় আরও একটি বিকল্প বাস্তবায়ন পাই । আমাদের কেবল আমাদের ডিকের মতো কাঠামোটি পাস করতে হবে json.dumps
। কিছুটা এইরকম:
def xml_to_json(xmlstr, **kwargs):
x = xml_to_dictlike(xmlstr, **kwargs)
return json.dumps(x)
যদি আপনার এক্সএমএলটিতে বৈশিষ্ট্যগুলি অন্তর্ভুক্ত থাকে attr_prefix
তবে কীগুলি বৈধ জেসন কীগুলি নিশ্চিত করার জন্য আপনাকে কিছু অক্ষর (যেমন "এটিটিআর_") ব্যবহার করতে হবে।
আমি এই অংশটি মানি না।