5fdcffed5f13b0759c07e894e3d541cbf635491a
[platform/upstream/gobject-introspection.git] / giscanner / xmlwriter.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
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.
9 #
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.
14 #
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.
19 #
20
21 from __future__ import with_statement
22
23 import os
24
25 from contextlib import contextmanager
26 from cStringIO import StringIO
27 from xml.sax.saxutils import escape
28
29 from .libtoolimporter import LibtoolImporter
30
31
32 with LibtoolImporter(None, None):
33     if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
34         from _giscanner import collect_attributes
35     else:
36         from giscanner._giscanner import collect_attributes
37
38
39 def build_xml_tag(tag_name, attributes=None, data=None, self_indent=0,
40                   self_indent_char=' '):
41     if attributes is None:
42         attributes = []
43     prefix = u'<%s' % (tag_name, )
44     if data is not None:
45         if isinstance(data, str):
46             data = data.decode('UTF-8')
47         suffix = u'>%s</%s>' % (escape(data), tag_name)
48     else:
49         suffix = u'/>'
50     attrs = collect_attributes(
51         tag_name, attributes,
52         self_indent,
53         self_indent_char,
54         len(prefix) + len(suffix))
55     return prefix + attrs + suffix
56
57
58 class XMLWriter(object):
59
60     def __init__(self):
61         self._data = StringIO()
62         self._data.write('<?xml version="1.0"?>\n')
63         self._tag_stack = []
64         self._indent = 0
65         self._indent_unit = 2
66         self.enable_whitespace()
67
68     # Private
69
70     def _open_tag(self, tag_name, attributes=None):
71         if attributes is None:
72             attributes = []
73         attrs = collect_attributes(tag_name, attributes,
74                                    self._indent, self._indent_char, len(tag_name) + 2)
75         self.write_line(u'<%s%s>' % (tag_name, attrs))
76
77     def _close_tag(self, tag_name):
78         self.write_line(u'</%s>' % (tag_name, ))
79
80     # Public API
81
82     def enable_whitespace(self):
83         self._indent_char = ' '
84         self._newline_char = '\n'
85
86     def disable_whitespace(self):
87         self._indent_char = ''
88         self._newline_char = ''
89
90     def get_xml(self):
91         return self._data.getvalue()
92
93     def write_line(self, line=u'', indent=True, do_escape=False):
94         if isinstance(line, str):
95             line = line.decode('utf-8')
96         assert isinstance(line, unicode)
97         if do_escape:
98             line = escape(line)
99         if indent:
100             self._data.write('%s%s%s' % (self._indent_char * self._indent,
101                                          line.encode('utf-8'),
102                                          self._newline_char))
103         else:
104             self._data.write('%s%s' % (line.encode('utf-8'), self._newline_char))
105
106     def write_comment(self, text):
107         self.write_line('<!-- %s -->' % (text, ))
108
109     def write_tag(self, tag_name, attributes, data=None):
110         self.write_line(build_xml_tag(tag_name, attributes, data,
111                                       self._indent, self._indent_char))
112
113     def push_tag(self, tag_name, attributes=None):
114         if attributes is None:
115             attributes = []
116         self._open_tag(tag_name, attributes)
117         self._tag_stack.append(tag_name)
118         self._indent += self._indent_unit
119
120     def pop_tag(self):
121         self._indent -= self._indent_unit
122         tag_name = self._tag_stack.pop()
123         self._close_tag(tag_name)
124         return tag_name
125
126     @contextmanager
127     def tagcontext(self, tag_name, attributes=None):
128         self.push_tag(tag_name, attributes)
129         try:
130             yield
131         finally:
132             self.pop_tag()
133
134
135 def test():
136     w = XMLWriter()
137     w.push_tag('repository')
138     w.push_tag('namespace')
139     w.push_tag('enumeration')
140     w.push_tag('member',
141                [('name', 'west'),
142                 ('value', '7'),
143                 ('c:identifier', 'GTK_ANCHOR_WEST'),
144                 ('glib:nick', 'west')])
145
146     w.pop_tag()
147     w.pop_tag()
148     w.pop_tag()
149     x = w.get_xml()
150     lines = x.split('\n')
151     import pprint
152     pprint.pprint(lines)
153     assert len(lines[3]) < 80, len(lines[3])
154
155 if __name__ == '__main__':
156     test()