changeset 461:af0122a5aa4b stable-0.4.x

Port [558] to 0.4.x.
author cmlenz
date Wed, 25 Apr 2007 19:42:12 +0000
parents 9101eb8a68b6
children 55d6a5a5e972
files ChangeLog genshi/core.py genshi/input.py genshi/output.py genshi/template/tests/markup.py genshi/tests/input.py
diffstat 6 files changed, 53 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,8 @@
 
  * Fix incorrect reference to translation function in the I18N filter.
  * The `ET()` function now correctly handles attributes with a namespace.
+ * XML declarations are now processed internally, as well as written to the
+   output when XML serialization is used (ticket #111).
 
 
 Version 0.4
--- a/genshi/core.py
+++ b/genshi/core.py
@@ -56,6 +56,7 @@
     START = StreamEventKind('START') #: a start tag
     END = StreamEventKind('END') #: an end tag
     TEXT = StreamEventKind('TEXT') #: literal text
+    XML_DECL = StreamEventKind('XML_DECL') #: XML declaration
     DOCTYPE = StreamEventKind('DOCTYPE') #: doctype declaration
     START_NS = StreamEventKind('START_NS') #: start namespace mapping
     END_NS = StreamEventKind('END_NS') #: end namespace mapping
@@ -208,6 +209,7 @@
 START = Stream.START
 END = Stream.END
 TEXT = Stream.TEXT
+XML_DECL = Stream.XML_DECL
 DOCTYPE = Stream.DOCTYPE
 START_NS = Stream.START_NS
 END_NS = Stream.END_NS
--- a/genshi/input.py
+++ b/genshi/input.py
@@ -26,7 +26,7 @@
 from StringIO import StringIO
 
 from genshi.core import Attrs, QName, Stream, stripentities
-from genshi.core import DOCTYPE, START, END, START_NS, END_NS, TEXT, \
+from genshi.core import START, END, XML_DECL, DOCTYPE, TEXT, START_NS, END_NS, \
                         START_CDATA, END_CDATA, PI, COMMENT
 
 __all__ = ['ET', 'ParseError', 'XMLParser', 'XML', 'HTMLParser', 'HTML']
@@ -123,6 +123,7 @@
         parser.StartCdataSectionHandler = self._handle_start_cdata
         parser.EndCdataSectionHandler = self._handle_end_cdata
         parser.ProcessingInstructionHandler = self._handle_pi
+        parser.XmlDeclHandler = self._handle_xml_decl
         parser.CommentHandler = self._handle_comment
 
         # Tell Expat that we'll handle non-XML entities ourselves
@@ -216,6 +217,9 @@
     def _handle_data(self, text):
         self._enqueue(TEXT, text)
 
+    def _handle_xml_decl(self, version, encoding, standalone):
+        self._enqueue(XML_DECL, (version, encoding, standalone))
+
     def _handle_doctype(self, name, sysid, pubid, has_internal_subset):
         self._enqueue(DOCTYPE, (name, pubid, sysid))
 
--- a/genshi/output.py
+++ b/genshi/output.py
@@ -23,7 +23,7 @@
 import re
 
 from genshi.core import escape, Attrs, Markup, Namespace, QName, StreamEventKind
-from genshi.core import DOCTYPE, START, END, START_NS, END_NS, TEXT, \
+from genshi.core import START, END, TEXT, XML_DECL, DOCTYPE, START_NS, END_NS, \
                         START_CDATA, END_CDATA, PI, COMMENT, XML_NAMESPACE
 
 __all__ = ['DocType', 'XMLSerializer', 'XHTMLSerializer', 'HTMLSerializer',
@@ -87,7 +87,7 @@
         self.filters.append(NamespaceFlattener(prefixes=namespace_prefixes))
 
     def __call__(self, stream):
-        have_doctype = False
+        have_decl = have_doctype = False
         in_cdata = False
 
         stream = chain(self.preamble, stream)
@@ -115,6 +115,18 @@
             elif kind is COMMENT:
                 yield Markup('<!--%s-->' % data)
 
+            elif kind is XML_DECL and not have_decl:
+                version, encoding, standalone = data
+                buf = ['<?xml version="%s"' % version]
+                if encoding:
+                    buf.append(' encoding="%s"' % encoding)
+                if standalone != -1:
+                    standalone = standalone and 'yes' or 'no'
+                    buf.append(' standalone="%s"' % standalone)
+                buf.append('?>\n')
+                yield Markup(u''.join(buf))
+                have_decl = True
+
             elif kind is DOCTYPE and not have_doctype:
                 name, pubid, sysid = data
                 buf = ['<!DOCTYPE %s']
--- a/genshi/template/tests/markup.py
+++ b/genshi/template/tests/markup.py
@@ -183,7 +183,7 @@
         <div xmlns:py="http://genshi.edgewall.org/">
           \xf6
         </div>""".encode('iso-8859-1'), encoding='iso-8859-1')
-        self.assertEqual(u"""<div>
+        self.assertEqual(u"""<?xml version="1.0" encoding="iso-8859-1"?>\n<div>
           \xf6
         </div>""", unicode(tmpl.generate()))
 
@@ -228,7 +228,7 @@
           <Size py:if="0" xmlns:t="test">Size</Size>
           <Item/>
         </Test>""")
-        self.assertEqual("""<Test>
+        self.assertEqual("""<?xml version="1.0"?>\n<Test>
           
           <Item/>
         </Test>""", str(tmpl.generate()))
--- a/genshi/tests/input.py
+++ b/genshi/tests/input.py
@@ -71,7 +71,7 @@
         <div>\xf6</div>
         """.encode('iso-8859-1')
         events = list(XMLParser(StringIO(text)))
-        kind, data, pos = events[1]
+        kind, data, pos = events[2]
         self.assertEqual(Stream.TEXT, kind)
         self.assertEqual(u'\xf6', data)
 
@@ -181,6 +181,33 @@
         self.assertEqual(u'php', target)
         self.assertEqual(u'echo "Foobar"', data)
 
+    def test_xmldecl(self):
+        text = '<?xml version="1.0" ?><root />'
+        events = list(XMLParser(StringIO(text)))
+        kind, (version, encoding, standalone), pos = events[0]
+        self.assertEqual(Stream.XML_DECL, kind)
+        self.assertEqual(u'1.0', version)
+        self.assertEqual(None, encoding)
+        self.assertEqual(-1, standalone)
+
+    def test_xmldecl_encoding(self):
+        text = '<?xml version="1.0" encoding="utf-8" ?><root />'
+        events = list(XMLParser(StringIO(text)))
+        kind, (version, encoding, standalone), pos = events[0]
+        self.assertEqual(Stream.XML_DECL, kind)
+        self.assertEqual(u'1.0', version)
+        self.assertEqual(u'utf-8', encoding)
+        self.assertEqual(-1, standalone)
+
+    def test_xmldecl_standalone(self):
+        text = '<?xml version="1.0" standalone="yes" ?><root />'
+        events = list(XMLParser(StringIO(text)))
+        kind, (version, encoding, standalone), pos = events[0]
+        self.assertEqual(Stream.XML_DECL, kind)
+        self.assertEqual(u'1.0', version)
+        self.assertEqual(None, encoding)
+        self.assertEqual(1, standalone)
+
     def test_processing_instruction_trailing_qmark(self):
         text = '<?php echo "Foobar" ??>'
         events = list(HTMLParser(StringIO(text)))
Copyright (C) 2012-2017 Edgewall Software