2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
21 from __future__ import with_statement
22 from __future__ import absolute_import
23 from __future__ import division
24 from __future__ import print_function
25 from __future__ import unicode_literals
30 from contextlib import contextmanager
31 from xml.sax.saxutils import escape
33 from .libtoolimporter import LibtoolImporter
35 if sys.version_info.major < 3:
36 from StringIO import StringIO
38 from io import StringIO
42 with LibtoolImporter(None, None):
43 if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
44 from _giscanner import collect_attributes
46 from giscanner._giscanner import collect_attributes
49 def build_xml_tag(tag_name, attributes=None, data=None, self_indent=0,
50 self_indent_char=' '):
51 if attributes is None:
53 prefix = '<%s' % (tag_name, )
55 if isinstance(data, bytes):
56 data = data.decode('UTF-8')
57 suffix = '>%s</%s>' % (escape(data), tag_name)
60 attrs = collect_attributes(
64 len(prefix) + len(suffix))
65 return prefix + attrs + suffix
68 class XMLWriter(object):
71 # Build up the XML buffer as unicode strings. When writing to disk,
72 # we can assume the lack of a Byte Order Mark (BOM) and lack
73 # of an "encoding" xml property means utf-8.
74 # See: http://www.opentag.com/xfaq_enc.htm#enc_default
75 self._data = StringIO()
76 self._data.write('<?xml version="1.0"?>\n')
80 self.enable_whitespace()
84 def _open_tag(self, tag_name, attributes=None):
85 if attributes is None:
87 attrs = collect_attributes(tag_name, attributes,
88 self._indent, self._indent_char, len(tag_name) + 2)
89 self.write_line('<%s%s>' % (tag_name, attrs))
91 def _close_tag(self, tag_name):
92 self.write_line('</%s>' % (tag_name, ))
96 def enable_whitespace(self):
97 self._indent_char = ' '
98 self._newline_char = '\n'
100 def disable_whitespace(self):
101 self._indent_char = ''
102 self._newline_char = ''
105 """Returns a unicode string containing the XML."""
106 return self._data.getvalue()
108 def get_encoded_xml(self):
109 """Returns a utf-8 encoded bytes object containing the XML."""
110 return self._data.getvalue().encode('utf-8')
112 def write_line(self, line='', indent=True, do_escape=False):
113 if isinstance(line, bytes):
114 line = line.decode('utf-8')
115 assert isinstance(line, unicode)
119 self._data.write('%s%s%s' % (self._indent_char * self._indent,
123 self._data.write('%s%s' % (line, self._newline_char))
125 def write_comment(self, text):
126 self.write_line('<!-- %s -->' % (text, ))
128 def write_tag(self, tag_name, attributes, data=None):
129 self.write_line(build_xml_tag(tag_name, attributes, data,
130 self._indent, self._indent_char))
132 def push_tag(self, tag_name, attributes=None):
133 if attributes is None:
135 self._open_tag(tag_name, attributes)
136 self._tag_stack.append(tag_name)
137 self._indent += self._indent_unit
140 self._indent -= self._indent_unit
141 tag_name = self._tag_stack.pop()
142 self._close_tag(tag_name)
146 def tagcontext(self, tag_name, attributes=None):
147 self.push_tag(tag_name, attributes)
156 w.push_tag('repository')
157 w.push_tag('namespace')
158 w.push_tag('enumeration')
162 ('c:identifier', 'GTK_ANCHOR_WEST'),
163 ('glib:nick', 'west')])
169 lines = x.split('\n')
172 assert len(lines[3]) < 80, len(lines[3])
174 if __name__ == '__main__':