2012-01-03 14 views
6

यहाँ एक सामान्य त्रुटि जब UTF-8 के साथ काम कर रहा है निकाला जा रहा है - 'अमान्य टोकन'अजगर UTF-8 XML पार्सिंग (साबुन का झाग): 'अमान्य टोकन'

मेरे उदाहरण में, यह एक सोप सेवा प्रदाता के साथ काम से आता है कि यूनिकोड वर्ण के लिए कोई सम्मान नहीं था, बस 100 बाइट्स मूल्यों को छोटा और उपेक्षा कि 100'th बाइट एक बहु बाइट वर्ण के बीच में हो सकता है: उदाहरण के लिए:

<name xsi:type="xsd:string">浙江家庭教会五十人遭驱散及抓打 圣诞节聚会被断电及抢走物品(图、视频\xef\xbc</name> 

पिछले दो बाइट्स क्या कर रहे हैं एक 3 बाइट यूनिकोड चरित्र के अवशेष, छिड़काव चाकू के बाद माना जाता है कि दुनिया 1-बाइट वर्णों का उपयोग करती है। अगला स्टॉप, सैक्स पार्सर और:

xml.sax._exceptions.SAXParseException: <unknown>:1:2392: not well-formed (invalid token) 

मुझे अब इस चरित्र की परवाह नहीं है। इसे दस्तावेज़ से हटा दिया जाना चाहिए और sax पार्सर को कार्य करने की अनुमति दें।

एक्सएमएल उत्तर इन मानों को छोड़कर हर दूसरे सम्मान में मान्य है।

प्रश्न: आप पूरे दस्तावेज़ को पार्स किए बिना इस चरित्र को कैसे हटा सकते हैं और प्रत्येक बाइट को जांचने के लिए यूटीएफ -8 एन्कोडिंग का पुन: आविष्कार कैसे कर सकते हैं?

का उपयोग करना: अजगर + साबुन का झाग

उत्तर

17

बाहर कर देता है, साबुन का झाग के रूप में प्रकार 'स्ट्रिंग' एक्सएमएल (नहीं यूनिकोड) को देखता है तो ये मान इनकोड।

1) फ़िल्टर:

badXML = "your bad utf-8 xml here" #(type <str>) 

#Turn it into a python unicode string - ignore errors, kick out bad unicode 
decoded = badXML.decode('utf-8', errors='ignore') #(type <unicode>) 

#turn it back into a string, using utf-8 encoding. 
goodXML = decoded.encode('utf-8') #(type <str>) 

2) साबुन का झाग: देखने https://fedorahosted.org/suds/wiki/Documentation#MessagePlugin

from suds.plugin import MessagePlugin 
class UnicodeFilter(MessagePlugin): 
    def received(self, context): 
     decoded = context.reply.decode('utf-8', errors='ignore') 
     reencoded = decoded.encode('utf-8') 
     context.reply = reencoded 

और

from suds.client import Client 
client = Client(WSDL_url, plugins=[UnicodeFilter()]) 

आशा इस कोई मदद करता है।


नोट: John Machin पर धन्यवाद!

देखें: Why is python decode replacing more than the invalid bytes from an encoded string?

अजगर issue8271errors='ignore' के बारे में यहाँ अपने तरीके से प्राप्त कर सकते हैं। इस बग अजगर में तय किए बिना, 'उपेक्षा' अगले कुछ बाइट्स का उपभोग गलत UTF-8 बाइट क्रम की डिकोडिंग, केवल
शुरू बाइट और निरंतरता बाइट (रों दौरान लंबाई

को पूरा करने के होगा
अजगर 2.6.6 RC1
अजगर 2.7.1 RC1 (और 2.7 के सभी भावी रिलीज़:) अब अमान्य माने जाते हैं, शुरू बाइट

मुद्दा द्वारा निर्दिष्ट बाइट्स की संख्या के बजाय में तय किया गया था)
पायथन 3.1.3 आरसी 1 (और 3.x की सभी भावी रिलीज)

पायथन 2.5 और नीचे इस समस्या को शामिल किया जाएगा।

उपरोक्त उदाहरण में, "\xef\xbc</name".decode('utf-8', errors='ignore')
"</name" लौट जाना चाहिए, लेकिन अजगर की 'जासूसी' संस्करणों में यह "/name" देता है।

पहले चार बिट्स (0xe) एक 3-बाइट UTF चरित्र है, तो बाइट्स 0xef, 0xbc, और उसके बाद (ग़लती से) 0x3c ('<') खपत होती है वर्णन करता है।

0x3c एक वैध निरंतरता बाइट नहीं है जो पहले स्थान पर अमान्य 3-बाइट यूटीएफ चरित्र बनाता है।

अजगर के फिक्स्ड संस्करण केवल पहली बाइट और ही मान्य निरंतरता बाइट्स निकालने के लिए, छोड़ने 0x3c unconsumed

+1

हाँ, मैं सिर्फ अपने ही सवाल का जवाब दे। : पी – FlipMcF

+0

आपके लिए अच्छा है। +1। – sberry

+0

स्वयं लर्नर बैज अर्जित किया ... (वह मुद्दा था, वास्तव में!) धन्यवाद। – FlipMcF

0

@ FlipMcF के सही जवाब है -, मैं सिर्फ उनके समाधान के लिए अपने फिल्टर पोस्टिंग कर रहा हूँ क्योंकि मूल एक मेरे लिए बाहर काम नहीं किया (मैं अपने एक्सएमएल, जो सही ढंग से UTF-8 में एन्कोड किए गए कुछ इमोजी था, लेकिन वे अभी भी एक्सएमएल पारसर्स दुर्घटनाग्रस्त हो गया):

class UnicodeFilter(MessagePlugin): 
    def received(self, context): 
     from lxml import etree 
     from StringIO import StringIO 
     parser = etree.XMLParser(recover=True) # recover=True is important here 
     doc = etree.parse(StringIO(context.reply), parser) 
     context.reply = etree.tostring(doc) 
संबंधित मुद्दे