سؤال

أنا أقنع بعض XML مع وظيفة ElementTree.Parse (). إنه يعمل، باستثناء بعض أحرف UTF-8 (حرف بايت واحد فوق 128). أرى أن المحلل الافتراضي هو xmltreeebuilder الذي يستند إلى Expat.

هل هناك محلل بديل يمكنني استخدامه قد يكون أقل صرامة وأسمح أحرف UTF-8؟

هذا هو الخطأ الذي أحصل عليه مع المحلل الافتراضي:

ExpatError: not well-formed (invalid token): line 311, column 190

الشخصية التي تسبب هذا هو بايت واحد x92 (في عرافة). أنا لست متأكدا من أن هذا هو حرف UTF-8 صالح. ولكن سيكون من الجميل التعامل معها لأن معظم محرري النصوص يعرضون هذا كما:

تعديل: سياق الشخصية هو: لا يزال، حيث أفترض أنه من المفترض أن يكون APOStraphe يتوهم، ولكن في محرر HEX، هذا التسلسل نفسه هو: 63 61 6E 92 74

هل كانت مفيدة؟

المحلول

سأبدأ من السؤال: "هل هناك محلل بديل يمكنني استخدامه قد يكون أقل صرامة وأسمح لأحرف UTF-8؟"

سيقبل جميع محلل XML البيانات المشفرة في UTF-8. في الواقع، UTF-8 هو الترميز الافتراضي.

قد يبدأ مستند XML بإعلان مثل هذا:

`<?xml version="1.0" encoding="UTF-8"?>`

او مثل هذا: <?xml version="1.0"?>أو ليس لديك إعلان على الإطلاق ... في كل حالة سيقوم المحلل بمدينة فك توثيق المستند باستخدام UTF-8.

ومع ذلك، لا يتم ترميز بياناتك في UTF-8 ... من المحتمل أن يكون Windows-1252 ويعرف أيضا باسم CP1252.

إذا لم يكن الترميز UTF-8، فعلي إما أن يتضمن الخالق إعلان (أو يمكن للمستلم بإعداد واحد) أو يمكن للمستلم تحويل البيانات إلى UTF-8. التالي يعرض ما يعمل وما لا:

>>> import xml.etree.ElementTree as ET
>>> from StringIO import StringIO as sio

>>> raw_text = '<root>can\x92t</root>' # text encoded in cp1252, no XML declaration

>>> t = ET.parse(sio(raw_text))
[tracebacks omitted]
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 9
# parser is expecting UTF-8

>>> t = ET.parse(sio('<?xml version="1.0" encoding="UTF-8"?>' + raw_text))
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 47
# parser is expecting UTF-8 again

>>> t = ET.parse(sio('<?xml version="1.0" encoding="cp1252"?>' + raw_text))
>>> t.getroot().text
u'can\u2019t'
# parser was told to expect cp1252; it works

>>> import unicodedata
>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
# not quite an apostrophe, but better than an exception

>>> fixed_text = raw_text.decode('cp1252').encode('utf8')
# alternative: we transcode the data to UTF-8

>>> t = ET.parse(sio(fixed_text))
>>> t.getroot().text
u'can\u2019t'
# UTF-8 is the default; no declaration needed

نصائح أخرى

يبدو أن لديك نص CP1252. إذا كان الأمر كذلك، فينبغي تحديدها في الجزء العلوي من الملف، على سبيل المثال:

<?xml version="1.0" encoding="CP1252" ?>

هذا يعمل مع elesstree.

إذا كنت تقوم بإنشاء هذه الملفات بنفسك، فلا تكتبها في هذا الترميز. احفظها كوحدة UTF-8 وقم بدورتك للمساعدة في قتل ترميزات النصية القديمة.

إذا كنت تتلقى بيانات CP1252 مع عدم وجود مواصفات ترميز، وأنت تعرف بالتأكيد أن الأمر سيكون دائما CP1252، فيمكنك فقط تحويله إلى UTF-8 قبل إرساله إلى المحلل:

s.decode("CP1252").encode("UTF-8")

البايت 0x92 غير صالح أبدا البايت الأول من حرف UTF-8. يمكن أن تكون صالحة مثل البايت اللاحقة. يرى هذا دليل UTF-8 للحصول على جدول من تسلسل البايت صالح.

هل يمكن أن تعطينا فكرة عن ما هي البايتات المحيطة بها 0x92؟ هل يشتمل إعلان XML على ترميز حرف؟

آه. هذا هو "لا يمكن"، من الواضح، وبالفعل، 0x92 هو النقاس في العديد من صفحات رمز Windows. يتحمل المحرر الخاص بك بدلا من ذلك أنه ملف Mac. ؛)

إذا كان من الأسفل، إصلاح الملف هو الشيء الصحيح الذي يجب القيام به. ولكن دائما تقريبا عندما تحتاج إلى استيراد آخر الشعوب XML، هناك الكثير من الأشياء التي لا توافق ببساطة على الترميز المعلن. لقد وجدت أن الحل الأفضل هو فك تشفير مع خطأ إعداد "XMLCharreFReplace"، وفي الحالات الشديدة يقوم بديل الأحرف المخصصة الخاصة بك يعمل على إصلاح المشاكل الأكثر شيوعا لهذا العميل المعين.

سأوصي أيضا LXML ككتابة XML في بيثون، لكن هذه ليست هي المشكلة هنا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top