Skip to content

Commit 1e04fcd

Browse files
committed
Initial progress with new SVG backend
1 parent 5df5830 commit 1e04fcd

File tree

6 files changed

+870
-617
lines changed

6 files changed

+870
-617
lines changed

lib/matplotlib/SimpleXMLWriter.py

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
#
2+
# SimpleXMLWriter
3+
# $Id: SimpleXMLWriter.py 2312 2005-03-02 18:13:39Z fredrik $
4+
#
5+
# a simple XML writer
6+
#
7+
# history:
8+
# 2001-12-28 fl created
9+
# 2002-11-25 fl fixed attribute encoding
10+
# 2002-12-02 fl minor fixes for 1.5.2
11+
# 2004-06-17 fl added pythondoc markup
12+
# 2004-07-23 fl added flush method (from Jay Graves)
13+
# 2004-10-03 fl added declaration method
14+
# 2011-03-30 mdboom modified to create proper indentation
15+
#
16+
# Copyright (c) 2001-2004 by Fredrik Lundh
17+
#
18+
# fredrik@pythonware.com
19+
# http://www.pythonware.com
20+
#
21+
# --------------------------------------------------------------------
22+
# The SimpleXMLWriter module is
23+
#
24+
# Copyright (c) 2001-2004 by Fredrik Lundh
25+
#
26+
# By obtaining, using, and/or copying this software and/or its
27+
# associated documentation, you agree that you have read, understood,
28+
# and will comply with the following terms and conditions:
29+
#
30+
# Permission to use, copy, modify, and distribute this software and
31+
# its associated documentation for any purpose and without fee is
32+
# hereby granted, provided that the above copyright notice appears in
33+
# all copies, and that both that copyright notice and this permission
34+
# notice appear in supporting documentation, and that the name of
35+
# Secret Labs AB or the author not be used in advertising or publicity
36+
# pertaining to distribution of the software without specific, written
37+
# prior permission.
38+
#
39+
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
40+
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
41+
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
42+
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
43+
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
44+
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45+
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
46+
# OF THIS SOFTWARE.
47+
# --------------------------------------------------------------------
48+
49+
##
50+
# Tools to write XML files, without having to deal with encoding
51+
# issues, well-formedness, etc.
52+
# <p>
53+
# The current version does not provide built-in support for
54+
# namespaces. To create files using namespaces, you have to provide
55+
# "xmlns" attributes and explicitly add prefixes to tags and
56+
# attributes.
57+
#
58+
# <h3>Patterns</h3>
59+
#
60+
# The following example generates a small XHTML document.
61+
# <pre>
62+
#
63+
# from elementtree.SimpleXMLWriter import XMLWriter
64+
# import sys
65+
#
66+
# w = XMLWriter(sys.stdout)
67+
#
68+
# html = w.start("html")
69+
#
70+
# w.start("head")
71+
# w.element("title", "my document")
72+
# w.element("meta", name="generator", value="my application 1.0")
73+
# w.end()
74+
#
75+
# w.start("body")
76+
# w.element("h1", "this is a heading")
77+
# w.element("p", "this is a paragraph")
78+
#
79+
# w.start("p")
80+
# w.data("this is ")
81+
# w.element("b", "bold")
82+
# w.data(" and ")
83+
# w.element("i", "italic")
84+
# w.data(".")
85+
# w.end("p")
86+
#
87+
# w.close(html)
88+
# </pre>
89+
##
90+
91+
import re, sys, string
92+
93+
try:
94+
unicode("")
95+
except NameError:
96+
def encode(s, encoding):
97+
# 1.5.2: application must use the right encoding
98+
return s
99+
_escape = re.compile(r"[&<>\"\x80-\xff]+") # 1.5.2
100+
else:
101+
def encode(s, encoding):
102+
return s.encode(encoding)
103+
_escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"'))
104+
105+
def encode_entity(text, pattern=_escape):
106+
# map reserved and non-ascii characters to numerical entities
107+
def escape_entities(m):
108+
out = []
109+
for char in m.group():
110+
out.append("&#%d;" % ord(char))
111+
return string.join(out, "")
112+
return encode(pattern.sub(escape_entities, text), "ascii")
113+
114+
del _escape
115+
116+
#
117+
# the following functions assume an ascii-compatible encoding
118+
# (or "utf-16")
119+
120+
def escape_cdata(s, encoding=None, replace=string.replace):
121+
s = replace(s, "&", "&amp;")
122+
s = replace(s, "<", "&lt;")
123+
s = replace(s, ">", "&gt;")
124+
if encoding:
125+
try:
126+
return encode(s, encoding)
127+
except UnicodeError:
128+
return encode_entity(s)
129+
return s
130+
131+
def escape_attrib(s, encoding=None, replace=string.replace):
132+
s = replace(s, "&", "&amp;")
133+
s = replace(s, "'", "&apos;")
134+
s = replace(s, "\"", "&quot;")
135+
s = replace(s, "<", "&lt;")
136+
s = replace(s, ">", "&gt;")
137+
if encoding:
138+
try:
139+
return encode(s, encoding)
140+
except UnicodeError:
141+
return encode_entity(s)
142+
return s
143+
144+
##
145+
# XML writer class.
146+
#
147+
# @param file A file or file-like object. This object must implement
148+
# a <b>write</b> method that takes an 8-bit string.
149+
# @param encoding Optional encoding.
150+
151+
class XMLWriter:
152+
153+
def __init__(self, file, encoding="us-ascii"):
154+
if not hasattr(file, "write"):
155+
file = open(file, "w")
156+
self.__write = file.write
157+
if hasattr(file, "flush"):
158+
self.flush = file.flush
159+
self.__open = 0 # true if start tag is open
160+
self.__tags = []
161+
self.__data = []
162+
self.__encoding = encoding
163+
164+
def __flush(self):
165+
# flush internal buffers
166+
if self.__open:
167+
self.__write(">\n")
168+
self.__open = 0
169+
if self.__data:
170+
data = string.join(self.__data, "")
171+
self.__write(escape_cdata(data, self.__encoding))
172+
self.__data = []
173+
174+
##
175+
# Writes an XML declaration.
176+
177+
def declaration(self):
178+
encoding = self.__encoding
179+
if encoding == "us-ascii" or encoding == "utf-8":
180+
self.__write("<?xml version='1.0'?>\n")
181+
else:
182+
self.__write("<?xml version='1.0' encoding='%s'?>\n" % encoding)
183+
184+
##
185+
# Opens a new element. Attributes can be given as keyword
186+
# arguments, or as a string/string dictionary. You can pass in
187+
# 8-bit strings or Unicode strings; the former are assumed to use
188+
# the encoding passed to the constructor. The method returns an
189+
# opaque identifier that can be passed to the <b>close</b> method,
190+
# to close all open elements up to and including this one.
191+
#
192+
# @param tag Element tag.
193+
# @param attrib Attribute dictionary. Alternatively, attributes
194+
# can be given as keyword arguments.
195+
# @return An element identifier.
196+
197+
def start(self, tag, attrib={}, **extra):
198+
self.__flush()
199+
tag = escape_cdata(tag, self.__encoding)
200+
self.__data = []
201+
self.__tags.append(tag)
202+
self.__write(" " * len(self.__tags))
203+
self.__write("<%s" % tag)
204+
if attrib or extra:
205+
attrib = attrib.copy()
206+
attrib.update(extra)
207+
attrib = attrib.items()
208+
attrib.sort()
209+
for k, v in attrib:
210+
k = escape_cdata(k, self.__encoding)
211+
v = escape_attrib(v, self.__encoding)
212+
self.__write(" %s=\"%s\"" % (k, v))
213+
self.__open = 1
214+
return len(self.__tags)-1
215+
216+
##
217+
# Adds a comment to the output stream.
218+
#
219+
# @param comment Comment text, as an 8-bit string or Unicode string.
220+
221+
def comment(self, comment):
222+
self.__flush()
223+
self.__write(" " * len(self.__tags))
224+
self.__write("<!-- %s -->\n" % escape_cdata(comment, self.__encoding))
225+
226+
##
227+
# Adds character data to the output stream.
228+
#
229+
# @param text Character data, as an 8-bit string or Unicode string.
230+
231+
def data(self, text):
232+
self.__data.append(text)
233+
234+
##
235+
# Closes the current element (opened by the most recent call to
236+
# <b>start</b>).
237+
#
238+
# @param tag Element tag. If given, the tag must match the start
239+
# tag. If omitted, the current element is closed.
240+
241+
def end(self, tag=None):
242+
if tag:
243+
assert self.__tags, "unbalanced end(%s)" % tag
244+
assert escape_cdata(tag, self.__encoding) == self.__tags[-1],\
245+
"expected end(%s), got %s" % (self.__tags[-1], tag)
246+
else:
247+
assert self.__tags, "unbalanced end()"
248+
tag = self.__tags.pop()
249+
if self.__data:
250+
self.__flush()
251+
elif self.__open:
252+
self.__open = 0
253+
self.__write("/>\n")
254+
return
255+
self.__write(" " * len(self.__tags))
256+
self.__write(" </%s>\n" % tag)
257+
258+
##
259+
# Closes open elements, up to (and including) the element identified
260+
# by the given identifier.
261+
#
262+
# @param id Element identifier, as returned by the <b>start</b> method.
263+
264+
def close(self, id):
265+
while len(self.__tags) > id:
266+
self.end()
267+
268+
##
269+
# Adds an entire element. This is the same as calling <b>start</b>,
270+
# <b>data</b>, and <b>end</b> in sequence. The <b>text</b> argument
271+
# can be omitted.
272+
273+
def element(self, tag, text=None, attrib={}, **extra):
274+
apply(self.start, (tag, attrib), extra)
275+
if text:
276+
self.data(text)
277+
self.end()
278+
279+
##
280+
# Flushes the output stream.
281+
282+
def flush(self):
283+
pass # replaced by the constructor

0 commit comments

Comments
 (0)