string = self.flatten()
return hashlib.sha1(string).digest()
+ def _clean_key(self, key):
+ """Replace spaces in keys with \\u00B7 (middle dot).
+
+ This character is deemed unlikely to occur in keys to our
+ playlist and curve info dictionaries, while many keys have
+ spaces in them.
+
+ \\u00B7 is allowed in XML 1.0 as of the 5th edition. See
+ the `4th edition errata`_ for details.
+
+ .. _4th edition errata:
+ http://www.w3.org/XML/xml-V10-4e-errata#E09
+ """
+ return key.replace(' ', u'\u00B7')
+
+ def _restore_key(self, key):
+ """Restore keys encoded with :meth:`_clean_key`.
+ """
+ return key.replace(u'\u00B7', ' ')
+
def flatten(self, absolute_paths=False):
"""Create a string representation of the playlist.
>>> c.info['note'] = 'The first curve'
>>> p.append(c)
>>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'two'))
- >>> c.info['note'] = 'The second curve\\nwith endlines'
+ >>> c.info['attr with spaces'] = 'The second curve\\nwith endlines'
>>> p.append(c)
- >>> print p.flatten() # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
+ >>> def _print(string):
+ ... escaped_string = unicode(string, 'utf-8').encode('unicode escape')
+ ... print escaped_string.replace('\\\\n', '\\n').replace('\\\\t', '\\t'),
+ >>> _print(p.flatten()) # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
<?xml version="1.0" encoding="utf-8"?>
<playlist index="0" note="An example playlist" version="0.1">
<curve note="The first curve" path="curve/one"/>
- <curve note="The second curve
with endlines" path="curve/two"/>
+ <curve attr\\xb7with\\xb7spaces="The second curve
with endlines" path="curve/two"/>
</playlist>
- <BLANKLINE>
- >>> print p.flatten(absolute_paths=True) # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
+ >>> _print(p.flatten(absolute_paths=True)) # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
<?xml version="1.0" encoding="utf-8"?>
<playlist index="0" note="An example playlist" version="0.1">
<curve note="The first curve" path="/path/to/curve/one"/>
- <curve note="The second curve
with endlines" path="/path/to/curve/two"/>
+ <curve attr\\xb7with\\xb7spaces="The second curve
with endlines" path="/path/to/curve/two"/>
</playlist>
- <BLANKLINE>
"""
implementation = xml.dom.minidom.getDOMImplementation()
# create the document DOM object and the root element
root.setAttribute('version', self.version) # store playlist version
root.setAttribute('index', str(self._index))
for key,value in self.info.items(): # save info variables
- root.setAttribute(key, str(value))
+ root.setAttribute(self._clean_key(key), str(value))
for curve in self: # save curves and their attributes
curve_element = doc.createElement('curve')
root.appendChild(curve_element)
for key,value in curve.info.items():
if key in self._ignored_keys:
continue
- curve_element.setAttribute(key,str(value))
+ curve_element.setAttribute(self._clean_key(key), str(value))
string = doc.toprettyxml(encoding='utf-8')
root.unlink() # break circular references for garbage collection
return string
"""
root = doc.documentElement
for attribute,value in root.attributes.items():
+ attribute = self._restore_key(attribute)
if attribute == 'version':
assert value == self.version, \
'Cannot read v%s playlist with a v%s reader' \
self.info[attribute] = value
for curve_element in doc.getElementsByTagName('curve'):
path = curve_element.getAttribute('path')
- info = dict(curve_element.attributes.items())
+ info = dict([(self._restore_key(key), value)
+ for key,value in curve_element.attributes.items()])
info.pop('path')
self.append_curve_by_path(path, info, identify=identify)
self.jump(self._index) # ensure valid index
def from_string(self, string, identify=True):
- """Load a playlist from a string.
+ u"""Load a playlist from a string.
Examples
--------
>>> string = '''<?xml version="1.0" encoding="utf-8"?>
... <playlist index="1" note="An example playlist" version="0.1">
... <curve note="The first curve" path="../curve/one"/>
- ... <curve note="The second curve
with endlines" path="../curve/two"/>
+ ... <curve attr\xb7with\xb7spaces="The second curve
with endlines" path="../curve/two"/>
... </playlist>
... '''
>>> p = FilePlaylist(drivers=[],
... print curve.path
path/to/curve/one
path/to/curve/two
- >>> p[-1].info['note']
+ >>> p[-1].info['attr with spaces']
u'The second curve\\nwith endlines'
"""
doc = xml.dom.minidom.parseString(string)