Code

svn repository setup
[roundup.git] / roundup / cgi / TAL / HTMLTALParser.py
index f1582f2f39cb46b12bedc1c3ca4e521f67a93b54..86de21890a9cc97ce05e1e1a3cd36d0504bf9471 100644 (file)
@@ -2,25 +2,25 @@
 #
 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
 # All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
-# 
+# FOR A PARTICULAR PURPOSE.
+#
 ##############################################################################
-"""Parse HTML and compile to TALInterpreter intermediate code.
 """
-__docformat__ = 'restructuredtext'
+Parse HTML and compile to TALInterpreter intermediate code.
+"""
 
 import sys
-import string
 
 from TALGenerator import TALGenerator
-from TALDefs import ZOPE_METAL_NS, ZOPE_TAL_NS, METALError, TALError
 from HTMLParser import HTMLParser, HTMLParseError
+from TALDefs import \
+     ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS, METALError, TALError, I18NError
 
 BOOLEAN_HTML_ATTRS = [
     # List of Boolean attributes in HTML that may be given in
@@ -75,7 +75,7 @@ class NestingError(HTMLParseError):
                        % (tagstack[0], endtag))
             else:
                 msg = ('Open tags <%s> do not match close tag </%s>'
-                       % (string.join(tagstack, '>, <'), endtag))
+                       % ('>, <'.join(tagstack), endtag))
         else:
             msg = 'No tags are open to match </%s>' % endtag
         HTMLParseError.__init__(self, msg, position)
@@ -107,13 +107,20 @@ class HTMLTALParser(HTMLParser):
         self.gen = gen
         self.tagstack = []
         self.nsstack = []
-        self.nsdict = {'tal': ZOPE_TAL_NS, 'metal': ZOPE_METAL_NS}
+        self.nsdict = {'tal': ZOPE_TAL_NS,
+                       'metal': ZOPE_METAL_NS,
+                       'i18n': ZOPE_I18N_NS,
+                       }
 
     def parseFile(self, file):
         f = open(file)
         data = f.read()
         f.close()
-        self.parseString(data)
+        try:
+            self.parseString(data)
+        except TALError, e:
+            e.setFile(file)
+            raise
 
     def parseString(self, data):
         self.feed(data)
@@ -133,9 +140,14 @@ class HTMLTALParser(HTMLParser):
     def handle_starttag(self, tag, attrs):
         self.close_para_tags(tag)
         self.scan_xmlns(attrs)
-        tag, attrlist, taldict, metaldict = self.process_ns(tag, attrs)
+        tag, attrlist, taldict, metaldict, i18ndict \
+             = self.process_ns(tag, attrs)
+        if tag in EMPTY_HTML_TAGS and taldict.get("content"):
+            raise TALError(
+                "empty HTML tags cannot use tal:content: %s" % `tag`,
+                self.getpos())
         self.tagstack.append(tag)
-        self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
+        self.gen.emitStartElement(tag, attrlist, taldict, metaldict, i18ndict,
                                   self.getpos())
         if tag in EMPTY_HTML_TAGS:
             self.implied_endtag(tag, -1)
@@ -143,14 +155,19 @@ class HTMLTALParser(HTMLParser):
     def handle_startendtag(self, tag, attrs):
         self.close_para_tags(tag)
         self.scan_xmlns(attrs)
-        tag, attrlist, taldict, metaldict = self.process_ns(tag, attrs)
+        tag, attrlist, taldict, metaldict, i18ndict \
+             = self.process_ns(tag, attrs)
         if taldict.get("content"):
+            if tag in EMPTY_HTML_TAGS:
+                raise TALError(
+                    "empty HTML tags cannot use tal:content: %s" % `tag`,
+                    self.getpos())
             self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
-                                      self.getpos())
+                                      i18ndict, self.getpos())
             self.gen.emitEndElement(tag, implied=-1)
         else:
             self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
-                                      self.getpos(), isend=1)
+                                      i18ndict, self.getpos(), isend=1)
         self.pop_xmlns()
 
     def handle_endtag(self, tag):
@@ -236,7 +253,7 @@ class HTMLTALParser(HTMLParser):
     def scan_xmlns(self, attrs):
         nsnew = {}
         for key, value in attrs:
-            if key[:6] == "xmlns:":
+            if key.startswith("xmlns:"):
                 nsnew[key[6:]] = value
         if nsnew:
             self.nsstack.append(self.nsdict)
@@ -250,10 +267,10 @@ class HTMLTALParser(HTMLParser):
 
     def fixname(self, name):
         if ':' in name:
-            prefix, suffix = string.split(name, ':', 1)
+            prefix, suffix = name.split(':', 1)
             if prefix == 'xmlns':
                 nsuri = self.nsdict.get(suffix)
-                if nsuri in (ZOPE_TAL_NS, ZOPE_METAL_NS):
+                if nsuri in (ZOPE_TAL_NS, ZOPE_METAL_NS, ZOPE_I18N_NS):
                     return name, name, prefix
             else:
                 nsuri = self.nsdict.get(prefix)
@@ -261,12 +278,15 @@ class HTMLTALParser(HTMLParser):
                     return name, suffix, 'tal'
                 elif nsuri == ZOPE_METAL_NS:
                     return name, suffix,  'metal'
+                elif nsuri == ZOPE_I18N_NS:
+                    return name, suffix, 'i18n'
         return name, name, 0
 
     def process_ns(self, name, attrs):
         attrlist = []
         taldict = {}
         metaldict = {}
+        i18ndict = {}
         name, namebase, namens = self.fixname(name)
         for item in attrs:
             key, value = item
@@ -284,7 +304,12 @@ class HTMLTALParser(HTMLParser):
                     raise METALError("duplicate METAL attribute " +
                                      `keybase`, self.getpos())
                 metaldict[keybase] = value
+            elif ns == 'i18n':
+                if i18ndict.has_key(keybase):
+                    raise I18NError("duplicate i18n attribute " +
+                                    `keybase`, self.getpos())
+                i18ndict[keybase] = value
             attrlist.append(item)
         if namens in ('metal', 'tal'):
             taldict['tal tag'] = namens
-        return name, attrlist, taldict, metaldict
+        return name, attrlist, taldict, metaldict, i18ndict