Index: genshi/tests/input.py
===================================================================
--- genshi/tests/input.py	(revision 1216)
+++ genshi/tests/input.py	(working copy)
@@ -177,6 +177,25 @@
         self.assertEqual('php', target)
         self.assertEqual('echo "Foobar"', data)
 
+    def test_processing_instruction_no_data_1(self):
+        text = u'<?foo ?>'
+        events = list(HTMLParser(StringIO(text)))
+        kind, (target, data), pos = events[0]
+        self.assertEqual(Stream.PI, kind)
+        self.assertEqual('foo', target)
+        self.assertEqual('', data)
+
+    def test_processing_instruction_no_data_2(self):
+        text = u'<?experiment>...<?/experiment>'
+        events = list(HTMLParser(StringIO(text)))
+        kind, (target, data), pos = events[0]
+        self.assertEqual(Stream.PI, kind)
+        self.assertEqual('experiment', target)
+        self.assertEqual('', data)
+        kind, (target, data), pos = events[2]
+        self.assertEqual('/experiment', target)
+        self.assertEqual('', data)
+
     def test_xmldecl(self):
         text = '<?xml version="1.0" ?><root />'
         events = list(XMLParser(StringIO(text)))
Index: genshi/input.py
===================================================================
--- genshi/input.py	(revision 1216)
+++ genshi/input.py	(working copy)
@@ -401,9 +401,14 @@
         self._enqueue(TEXT, text)
 
     def handle_pi(self, data):
-        target, data = data.split(None, 1)
         if data.endswith('?'):
             data = data[:-1]
+        try:
+            target, data = data.split(None, 1)
+        except ValueError:
+            # PI with no data
+            target = data
+            data = ''
         self._enqueue(PI, (target.strip(), data.strip()))
 
     def handle_comment(self, text):
