~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/xml_serializer.py

  • Committer: John Arbash Meinel
  • Date: 2009-06-02 19:56:24 UTC
  • mto: This revision was merged to the branch mainline in revision 4469.
  • Revision ID: john@arbash-meinel.com-20090602195624-utljsyz0qgmq63lg
Add a chunks_to_gzip function.
This allows the _record_to_data code to build up a list of chunks,
rather than requiring a single string.
It should be ~ the same performance when using a single string, since
we are only adding a for() loop over the chunks and an if check.
We could possibly just remove the if check and not worry about adding
some empty strings in there.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
22
22
# importing this module is fairly slow because it has to load several
23
23
# ElementTree bits
24
24
 
25
 
import re
26
 
 
27
25
from bzrlib.serializer import Serializer
28
 
from bzrlib.trace import mutter
 
26
from bzrlib.trace import mutter, warning
29
27
 
30
28
try:
31
29
    try:
33
31
        from xml.etree.cElementTree import (ElementTree, SubElement, Element,
34
32
            XMLTreeBuilder, fromstring, tostring)
35
33
        import xml.etree as elementtree
36
 
        # Also import ElementTree module so monkey-patching below always works
37
 
        import xml.etree.ElementTree
38
34
    except ImportError:
39
35
        from cElementTree import (ElementTree, SubElement, Element,
40
36
                                  XMLTreeBuilder, fromstring, tostring)
56
52
class XMLSerializer(Serializer):
57
53
    """Abstract XML object serialize/deserialize"""
58
54
 
59
 
    squashes_xml_invalid_characters = True
60
 
 
61
55
    def read_inventory_from_string(self, xml_string, revision_id=None,
62
 
                                   entry_cache=None, return_from_cache=False):
 
56
                                   entry_cache=None):
63
57
        """Read xml_string into an inventory object.
64
58
 
65
59
        :param xml_string: The xml to read.
73
67
        :param entry_cache: An optional cache of InventoryEntry objects. If
74
68
            supplied we will look up entries via (file_id, revision_id) which
75
69
            should map to a valid InventoryEntry (File/Directory/etc) object.
76
 
        :param return_from_cache: Return entries directly from the cache,
77
 
            rather than copying them first. This is only safe if the caller
78
 
            promises not to mutate the returned inventory entries, but it can
79
 
            make some operations significantly faster.
80
70
        """
81
71
        try:
82
72
            return self._unpack_inventory(fromstring(xml_string), revision_id,
83
 
                                          entry_cache=entry_cache,
84
 
                                          return_from_cache=return_from_cache)
 
73
                                          entry_cache=entry_cache)
85
74
        except ParseError, e:
86
75
            raise errors.UnexpectedInventoryFormat(e)
87
76
 
88
77
    def read_inventory(self, f, revision_id=None):
89
78
        try:
90
 
            try:
91
 
                return self._unpack_inventory(self._read_element(f),
92
 
                    revision_id=None)
93
 
            finally:
94
 
                f.close()
 
79
            return self._unpack_inventory(self._read_element(f),
 
80
                revision_id=None)
95
81
        except ParseError, e:
96
82
            raise errors.UnexpectedInventoryFormat(e)
97
83
 
115
101
        return ElementTree().parse(f)
116
102
 
117
103
 
 
104
# performance tuning for elementree's serialiser. This should be
 
105
# sent upstream - RBC 20060523.
 
106
# the functions here are patched into elementtree at runtime.
 
107
import re
 
108
escape_re = re.compile("[&'\"<>]")
 
109
escape_map = {
 
110
    "&":'&amp;',
 
111
    "'":"&apos;", # FIXME: overkill
 
112
    "\"":"&quot;",
 
113
    "<":"&lt;",
 
114
    ">":"&gt;",
 
115
    }
 
116
def _escape_replace(match, map=escape_map):
 
117
    return map[match.group()]
 
118
 
 
119
def _escape_attrib(text, encoding=None, replace=None):
 
120
    # escape attribute value
 
121
    try:
 
122
        if encoding:
 
123
            try:
 
124
                text = elementtree.ElementTree._encode(text, encoding)
 
125
            except UnicodeError:
 
126
                return elementtree.ElementTree._encode_entity(text)
 
127
        if replace is None:
 
128
            return escape_re.sub(_escape_replace, text)
 
129
        else:
 
130
            text = replace(text, "&", "&amp;")
 
131
            text = replace(text, "'", "&apos;") # FIXME: overkill
 
132
            text = replace(text, "\"", "&quot;")
 
133
            text = replace(text, "<", "&lt;")
 
134
            text = replace(text, ">", "&gt;")
 
135
            return text
 
136
    except (TypeError, AttributeError):
 
137
        elementtree.ElementTree._raise_serialization_error(text)
 
138
 
 
139
elementtree.ElementTree._escape_attrib = _escape_attrib
 
140
 
 
141
escape_cdata_re = re.compile("[&<>]")
 
142
escape_cdata_map = {
 
143
    "&":'&amp;',
 
144
    "<":"&lt;",
 
145
    ">":"&gt;",
 
146
    }
 
147
def _escape_cdata_replace(match, map=escape_cdata_map):
 
148
    return map[match.group()]
 
149
 
 
150
def _escape_cdata(text, encoding=None, replace=None):
 
151
    # escape character data
 
152
    try:
 
153
        if encoding:
 
154
            try:
 
155
                text = elementtree.ElementTree._encode(text, encoding)
 
156
            except UnicodeError:
 
157
                return elementtree.ElementTree._encode_entity(text)
 
158
        if replace is None:
 
159
            return escape_cdata_re.sub(_escape_cdata_replace, text)
 
160
        else:
 
161
            text = replace(text, "&", "&amp;")
 
162
            text = replace(text, "<", "&lt;")
 
163
            text = replace(text, ">", "&gt;")
 
164
            return text
 
165
    except (TypeError, AttributeError):
 
166
        elementtree.ElementTree._raise_serialization_error(text)
 
167
 
 
168
elementtree.ElementTree._escape_cdata = _escape_cdata
 
169
 
 
170
 
118
171
def escape_invalid_chars(message):
119
172
    """Escape the XML-invalid characters in a commit message.
120
173
 
121
174
    :param message: Commit message to escape
122
175
    :return: tuple with escaped message and number of characters escaped
123
176
    """
124
 
    if message is None:
125
 
        return None, 0
126
177
    # Python strings can include characters that can't be
127
178
    # represented in well-formed XML; escape characters that
128
179
    # aren't listed in the XML specification