# -*- Mode: Python -*- # GObject-Introspection - a framework for introspecting GObject libraries # Copyright (C) 2008 Johan Dahlin # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # from __future__ import with_statement from contextlib import contextmanager from cStringIO import StringIO from xml.sax.saxutils import quoteattr from .libtoolimporter import LibtoolImporter def _calc_attrs_length(attributes, indent, self_indent): if indent == -1: return -1 attr_length = 0 for attr, value in attributes: # FIXME: actually, if we have attributes with None as value this # should be considered a bug and raise an error. We are just # ignoring them here while we fix GIRParser to create the right # ast with the correct attributes. if value is None: continue attr_length += 2 + len(attr) + len(quoteattr(value)) return attr_length + indent + self_indent def collect_attributes(tag_name, attributes, self_indent, self_indent_char, indent=-1): if not attributes: return '' if _calc_attrs_length(attributes, indent, self_indent) > 79: indent_len = self_indent + len(tag_name) + 1 else: indent_len = 0 first = True attr_value = '' for attr, value in attributes: # FIXME: actually, if we have attributes with None as value this # should be considered a bug and raise an error. We are just # ignoring them here while we fix GIRParser to create the right # ast with the correct attributes. if value is None: continue if indent_len and not first: attr_value += '\n%s' % (self_indent_char * indent_len) attr_value += ' %s=%s' % (attr, quoteattr(value)) if first: first = False return attr_value with LibtoolImporter: from giscanner._giscanner import collect_attributes class XMLWriter(object): def __init__(self): self._data = StringIO() self._data.write('\n') self._tag_stack = [] self._indent = 0 self._indent_unit = 2 self._indent_char = ' ' # Private def _open_tag(self, tag_name, attributes=None): attrs = collect_attributes( tag_name, attributes, self._indent, self._indent_char, len(tag_name) + 2) self.write_line('<%s%s>' % (tag_name, attrs)) def _close_tag(self, tag_name): self.write_line('' % (tag_name, )) # Public API def get_xml(self): return self._data.getvalue() def write_line(self, line=''): self._data.write('%s%s\n' % (self._indent_char * self._indent, line)) def write_comment(self, text): self.write_line('' % (text, )) def write_tag(self, tag_name, attributes, data=None): if attributes is None: attributes = [] prefix = '<%s' % (tag_name, ) if data is not None: suffix = '>%s' % (data, tag_name) else: suffix = '/>' attrs = collect_attributes( tag_name, attributes, self._indent, self._indent_char, len(prefix) + len(suffix)) self.write_line(prefix + attrs + suffix) def push_tag(self, tag_name, attributes=None): if attributes is None: attributes = [] self._open_tag(tag_name, attributes) self._tag_stack.append(tag_name) self._indent += self._indent_unit def pop_tag(self): self._indent -= self._indent_unit tag_name = self._tag_stack.pop() self._close_tag(tag_name) return tag_name @contextmanager def tagcontext(self, tag_name, attributes=None): self.push_tag(tag_name, attributes) try: yield finally: self.pop_tag() def test(): w = XMLWriter() w.push_tag('repository') w.push_tag('namespace') w.push_tag('enumeration') w.push_tag('member', [('name', 'west'), ('value', '7'), ('c:identifier', 'GTK_ANCHOR_WEST'), ('glib:nick', 'west')]) w.pop_tag() w.pop_tag() w.pop_tag() x = w.get_xml() lines = x.split('\n') import pprint pprint.pprint(lines) assert len(lines[3]) < 80, len(lines[3]) if __name__ == '__main__': test()