text: #encoding=utf-8
  
  from xml.dom import minidom
  import collections
  import time
  
  
  def kv2element(key, value, doc):
      ele = doc.createElement(key)
      if isinstance(value, str) or isinstance(value, unicode):
          data = doc.createCDATASection(value)
          ele.appendChild(data)
      else:
          text = doc.createTextNode(str(value))
          ele.appendChild(text)
      return ele
  
  
  def fields2elements(tupleObj, enclose_tag=None, doc=None):
      if enclose_tag:
          xml = doc.createElement(enclose_tag)
          for key in tupleObj._fields:
              ele = kv2element(key, getattr(tupleObj, key), doc)
              xml.appendChild(ele)
          return xml
      else:
          return [kv2element(key, getattr(tupleObj, key), doc)
                  for key in tupleObj._fields]
  
  
  class WxRequest(object):
  
      def __init__(self, xml=None):
          if not xml:
              return
          doc = minidom.parseString(xml)
          params = [ele for ele in doc.childNodes[0].childNodes
                    if isinstance(ele, minidom.Element)]
          for param in params:
              if param.childNodes:
                  text = param.childNodes[0]
                  self.__dict__.update({param.tagName: text.data})
              else:
                  self.__dict__.update({param.tagName: ''})
  
  
  class WxResponse(object):
  
      def __init__(self, request):
          self.CreateTime = long(time.time())
          self.ToUserName = request.FromUserName
          self.FromUserName = request.ToUserName
          self.Extra = {}
  
      def as_xml(self):
          doc = minidom.Document()
          xml = doc.createElement('xml')
          doc.appendChild(xml)
          xml.appendChild(kv2element('ToUserName', self.ToUserName, doc))
          xml.appendChild(kv2element('FromUserName', self.FromUserName, doc))
          xml.appendChild(kv2element('CreateTime', self.CreateTime, doc))
          xml.appendChild(kv2element('MsgType', self.MsgType, doc))
          contents = self.content_nodes(doc)
          if isinstance(contents, list) or isinstance(contents, tuple):
              for content in contents:
                  xml.appendChild(content)
          else:
              xml.appendChild(contents)
          if self.Extra:
              for key, value in self.Extra.iteritems():
                  xml.appendChild(kv2element(key, value, doc))
          return doc.toxml()
  
  
  WxMusic = collections.namedtuple('WxMusic',
                                   'Title Description MusicUrl HQMusicUrl')
  WxArticle = collections.namedtuple('WxArticle',
                                     'Title Description PicUrl Url')
  WxImage = collections.namedtuple('WxImage', 'MediaId')
  WxVoice = collections.namedtuple('WxVoice', 'MediaId')
  WxVideo = collections.namedtuple('WxVideo',
                                   'MediaId Title Description')
  WxLink = collections.namedtuple('WxLink', 'Title Description Url')
  
  
  class WxEmptyResponse(WxResponse):
  
      def __init__(self):
          pass
  
      def as_xml(self):
          return ''
  
  
  class WxTextResponse(WxResponse):
  
      MsgType = 'text'
  
      def __init__(self, text, request):
          super(WxTextResponse, self).__init__(request)
          self.text = text
  
      def content_nodes(self, doc):
          return kv2element('Content', self.text, doc)
  
  
  class WxCompoundResponse(WxResponse):
  
      MsgType = ''
      Tag = ''
  
      def __init__(self, data, request):
          super(WxCompoundResponse, self).__init__(request)
          self.data = data
  
      def content_nodes(self, doc):
          return fields2elements(self.data, self.Tag, doc)
  
  
  class WxImageResponse(WxCompoundResponse):
  
      MsgType = 'image'
      Tag = 'Image'
  
  
  class WxVoiceResponse(WxCompoundResponse):
  
      MsgType = 'voice'
      Tag = 'Voice'
  
  
  class WxVideoResponse(WxCompoundResponse):
  
      MsgType = 'video'
      Tag = 'Video'
  
  
  class WxMusicResponse(WxResponse):
  
      MsgType = 'music'
      Tag = 'Music'
  
  
  class WxNewsResponse(WxResponse):
  
      MsgType = 'news'
  
      def __init__(self, articles, request):
          super(WxNewsResponse, self).__init__(request)
          if isinstance(articles, list) or isinstance(articles, tuple):
              self.articles = articles
          else:
              self.articles = [articles]
  
      def content_nodes(self, doc):
          count = kv2element('ArticleCount', len(self.articles), doc)
          articles = doc.createElement('Articles')
          for article in self.articles:
              articles.appendChild(fields2elements(article, 'item', doc))
          return count, articles
  
  
  class APIError(object):
  
      def __init__(self, code, msg):
          self.code = code
          self.message = msg
  