1616
1717
1818# This module is used for version 2 of the Google Data APIs.
19- # TODO: handle UTF-8 and unicode as done in src/atom/__init__.py
2019
2120
2221__author__ = 'j.s@google.com (Jeff Scudder)'
4140class XmlElement (object ):
4241 """Represents an element node in an XML document.
4342
44- The text member is a UTF-8 encoded str.
43+ The text member is a UTF-8 encoded str or unicode .
4544 """
4645 _qname = None
4746 _other_elements = None
4847 _other_attributes = None
48+ # The rule set contains mappings for XML qnames to child members and the
49+ # appropriate member classes.
4950 _rule_set = None
5051 _members = None
5152 text = None
@@ -96,6 +97,33 @@ def _list_xml_members(cls):
9697 _list_xml_members = classmethod (_list_xml_members )
9798
9899 def _get_rules (cls , version ):
100+ """Initializes the _rule_set for the class which is used when parsing XML.
101+
102+ This method is used internally for parsing and generating XML for an
103+ XmlElement. It is not recommended that you call this method directly.
104+
105+ Returns:
106+ A tuple containing the XML parsing rules for the appropriate version.
107+
108+ The tuple looks like:
109+ (qname, {sub_element_qname: (member_name, member_class, repeating), ..},
110+ {attribute_qname: member_name})
111+
112+ To give a couple of concrete example, the atom.data.Control _get_rules
113+ with version of 2 will return:
114+ ('{http://www.w3.org/2007/app}control',
115+ {'{http://www.w3.org/2007/app}draft': ('draft',
116+ <class 'atom.data.Draft'>,
117+ False)},
118+ {})
119+ Calling _get_rules with version 1 on gdata.data.FeedLink will produce:
120+ ('{http://schemas.google.com/g/2005}feedLink',
121+ {'{http://www.w3.org/2005/Atom}feed': ('feed',
122+ <class 'gdata.data.GDFeed'>,
123+ False)},
124+ {'href': 'href', 'readOnly': 'read_only', 'countHint': 'count_hint',
125+ 'rel': 'rel'})
126+ """
99127 # Initialize the _rule_set to make sure there is a slot available to store
100128 # the parsing rules for this version of the XML schema.
101129 # Look for rule set in the class __dict__ proxy so that only the
@@ -190,6 +218,14 @@ def get_elements(self, tag=None, namespace=None, version=1):
190218 return matches
191219
192220 GetElements = get_elements
221+ # FindExtensions and FindChildren are provided for backwards compatibility
222+ # to the atom.AtomBase class.
223+ # However, FindExtensions may return more results than the v1 atom.AtomBase
224+ # method does, because get_elements searches both the expected children
225+ # and the unexpected "other elements". The old AtomBase.FindExtensions
226+ # method searched only "other elements" AKA extension_elements.
227+ FindExtensions = get_elements
228+ FindChildren = get_elements
193229
194230 def get_attributes (self , tag = None , namespace = None , version = 1 ):
195231 """Find all attributes which match the tag and namespace.
@@ -266,6 +302,7 @@ def _attach_members(self, tree, version=1, encoding=None):
266302 other_attributes and other_elements are also added a children
267303 of this tree.
268304 version: int Ingnored in this method but used by VersionedElement.
305+ encoding: str (optional)
269306 """
270307 qname , elements , attributes = self .__class__ ._get_rules (version )
271308 encoding = encoding or STRING_ENCODING
@@ -335,28 +372,47 @@ def __set_extension_attributes(self, attributes):
335372 __set_extension_attributes ,
336373 """Provides backwards compatibility for v1 atom.AtomBase classes.""" )
337374
338- def __get_tag (self ):
339- return self ._qname [self ._qname .find ('}' )+ 1 :]
375+ def _get_tag (self , version = 1 ):
376+ qname = _get_qname (self , version )
377+ return qname [qname .find ('}' )+ 1 :]
340378
341- def __get_namespace (self ):
342- if self ._qname .startswith ('{' ):
343- return self ._qname [1 :self ._qname .find ('}' )]
379+ def _get_namespace (self , version = 1 ):
380+ qname = _get_qname (self , version )
381+ if qname .startswith ('{' ):
382+ return qname [1 :qname .find ('}' )]
344383 else :
345384 return None
346385
347- def __set_tag (self , tag ):
348- if self ._qname .startswith ('{' ):
349- self ._qname = '{%s}%s' % (self .__get_namespace (), tag )
386+ def _set_tag (self , tag ):
387+ if isinstance (self ._qname , tuple ):
388+ self ._qname = self ._qname .copy ()
389+ if self ._qname [0 ].startswith ('{' ):
390+ self ._qname [0 ] = '{%s}%s' % (self ._get_namespace (1 ), tag )
391+ else :
392+ self ._qname [0 ] = tag
350393 else :
351- self ._qname = tag
394+ if self ._qname .startswith ('{' ):
395+ self ._qname = '{%s}%s' % (self ._get_namespace (), tag )
396+ else :
397+ self ._qname = tag
352398
353- def __set_namespace (self , namespace ):
354- self ._qname = '{%s}%s' % (namespace , self .__get_tag ())
399+ def _set_namespace (self , namespace ):
400+ if isinstance (self ._qname , tuple ):
401+ self ._qname = self ._qname .copy ()
402+ if namespace :
403+ self ._qname [0 ] = '{%s}%s' % (namespace , self ._get_tag (1 ))
404+ else :
405+ self ._qname [0 ] = self ._get_tag (1 )
406+ else :
407+ if namespace :
408+ self ._qname = '{%s}%s' % (namespace , self ._get_tag (1 ))
409+ else :
410+ self ._qname = self ._get_tag (1 )
355411
356- tag = property (__get_tag , __set_tag ,
412+ tag = property (_get_tag , _set_tag ,
357413 """Provides backwards compatibility for v1 atom.AtomBase classes.""" )
358414
359- namespace = property (__get_namespace , __set_namespace ,
415+ namespace = property (_get_namespace , _set_namespace ,
360416 """Provides backwards compatibility for v1 atom.AtomBase classes.""" )
361417
362418 # Provided for backwards compatibility to atom.ExtensionElement
@@ -444,6 +500,7 @@ def parse(xml_string, target_class=None, version=1, encoding=None):
444500 return _xml_element_from_tree (tree , target_class , version )
445501
446502
503+ Parse = parse
447504xml_element_from_string = parse
448505XmlElementFromString = xml_element_from_string
449506
@@ -457,7 +514,7 @@ def _xml_element_from_tree(tree, target_class, version=1):
457514 # TODO handle the namespace-only case
458515 # Namespace only will be used with Google Spreadsheets rows and
459516 # Google Base item attributes.
460- elif tree .tag == target_class . _qname :
517+ elif tree .tag == _get_qname ( target_class , version ) :
461518 instance = target_class ()
462519 instance ._harvest_tree (tree , version )
463520 return instance
0 commit comments