From c8afa65dcb3458319a50db08628dec441fe3f482 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 27 Jul 2017 20:44:26 +0200 Subject: [PATCH] tools/xmlparser: implement writer --- nemubot/tools/test_xmlparser.py | 36 +++++++++++++++++++++++--- nemubot/tools/xmlparser/__init__.py | 15 +++++++++++ nemubot/tools/xmlparser/basic.py | 14 ++++++++++ nemubot/tools/xmlparser/genericnode.py | 8 ++++++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/nemubot/tools/test_xmlparser.py b/nemubot/tools/test_xmlparser.py index d7f5a9a..0feda73 100644 --- a/nemubot/tools/test_xmlparser.py +++ b/nemubot/tools/test_xmlparser.py @@ -1,5 +1,6 @@ import unittest +import io import xml.parsers.expat from nemubot.tools.xmlparser import XMLParser @@ -12,6 +13,11 @@ class StringNode(): def characters(self, content): self.string += content + def saveElement(self, store, tag="string"): + store.startElement(tag, {}) + store.characters(self.string) + store.endElement(tag) + class TestNode(): def __init__(self, option=None): @@ -22,6 +28,15 @@ class TestNode(): self.mystr = child.string return True + def saveElement(self, store, tag="test"): + store.startElement(tag, {"option": self.option}) + + strNode = StringNode() + strNode.string = self.mystr + strNode.saveElement(store) + + store.endElement(tag) + class Test2Node(): def __init__(self, option=None): @@ -33,6 +48,15 @@ class Test2Node(): self.mystrs.append(attrs["value"]) return True + def saveElement(self, store, tag="test"): + store.startElement(tag, {"option": self.option} if self.option is not None else {}) + + for mystr in self.mystrs: + store.startElement("string", {"value": mystr}) + store.endElement("string") + + store.endElement(tag) + class TestXMLParser(unittest.TestCase): @@ -44,9 +68,11 @@ class TestXMLParser(unittest.TestCase): p.CharacterDataHandler = mod.characters p.EndElementHandler = mod.endElement - p.Parse("toto", 1) + inputstr = "toto" + p.Parse(inputstr, 1) self.assertEqual(mod.root.string, "toto") + self.assertEqual(mod.saveDocument(header=False).getvalue(), inputstr) def test_parser2(self): @@ -57,10 +83,12 @@ class TestXMLParser(unittest.TestCase): p.CharacterDataHandler = mod.characters p.EndElementHandler = mod.endElement - p.Parse("toto", 1) + inputstr = 'toto' + p.Parse(inputstr, 1) self.assertEqual(mod.root.option, "123") self.assertEqual(mod.root.mystr, "toto") + self.assertEqual(mod.saveDocument(header=False).getvalue(), inputstr) def test_parser3(self): @@ -71,12 +99,14 @@ class TestXMLParser(unittest.TestCase): p.CharacterDataHandler = mod.characters p.EndElementHandler = mod.endElement - p.Parse("", 1) + inputstr = '' + p.Parse(inputstr, 1) self.assertEqual(mod.root.option, None) self.assertEqual(len(mod.root.mystrs), 2) self.assertEqual(mod.root.mystrs[0], "toto") self.assertEqual(mod.root.mystrs[1], "toto2") + self.assertEqual(mod.saveDocument(header=False, short_empty_elements=True).getvalue(), inputstr) if __name__ == '__main__': diff --git a/nemubot/tools/xmlparser/__init__.py b/nemubot/tools/xmlparser/__init__.py index abc5bb9..c8d393a 100644 --- a/nemubot/tools/xmlparser/__init__.py +++ b/nemubot/tools/xmlparser/__init__.py @@ -134,6 +134,21 @@ class XMLParser: return raise TypeError(name + " tag not expected in " + self.display_stack()) + def saveDocument(self, f=None, header=True, short_empty_elements=False): + if f is None: + import io + f = io.StringIO() + + import xml.sax.saxutils + gen = xml.sax.saxutils.XMLGenerator(f, "utf-8", short_empty_elements=short_empty_elements) + if header: + gen.startDocument() + self.root.saveElement(gen) + if header: + gen.endDocument() + + return f + def parse_file(filename): p = xml.parsers.expat.ParserCreate() diff --git a/nemubot/tools/xmlparser/basic.py b/nemubot/tools/xmlparser/basic.py index 8456629..f2d9fd5 100644 --- a/nemubot/tools/xmlparser/basic.py +++ b/nemubot/tools/xmlparser/basic.py @@ -44,6 +44,13 @@ class ListNode: return self.items.__repr__() + def saveElement(self, store, tag="list"): + store.startElement(tag, {}) + for i in self.items: + i.saveElement(store) + store.endElement(tag) + + class DictNode: """XML node representing a Python dictionnnary @@ -106,3 +113,10 @@ class DictNode: def __repr__(self): return self.items.__repr__() + + + def saveElement(self, store, tag="dict"): + store.startElement(tag, {}) + for k, v in self.items.items(): + v.saveElement(store) + store.endElement(tag) diff --git a/nemubot/tools/xmlparser/genericnode.py b/nemubot/tools/xmlparser/genericnode.py index 9c29a23..425934c 100644 --- a/nemubot/tools/xmlparser/genericnode.py +++ b/nemubot/tools/xmlparser/genericnode.py @@ -53,6 +53,14 @@ class ParsingNode: return item in self.attrs + def saveElement(self, store, tag=None): + store.startElement(tag if tag is not None else self.tag, self.attrs) + for child in self.children: + child.saveElement(store) + store.characters(self.content) + store.endElement(tag if tag is not None else self.tag) + + class GenericNode(ParsingNode): """Consider all subtags as dictionnary