=================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/base.py,v retrieving revision 1.3 diff -u -r1.3 base.py --- src/feedvalidator/base.py 7 Feb 2004 14:23:19 -0000 1.3 +++ src/feedvalidator/base.py 12 Feb 2004 17:25:02 -0000 @@ -8,6 +8,7 @@ from xml.sax.handler import ContentHandler from xml.sax.xmlreader import Locator +from sets import ImmutableSet # references: # http://web.resource.org/rss/1.0/modules/standard.html @@ -199,6 +200,9 @@ self.isValid = 1 self.name = None + def getExpectedAttrNames(self): + None + def unknown_starttag(self, name, qname, attrs): from validators import eater return eater() @@ -251,6 +255,13 @@ def endElementNS(self, name, qname): self.value=self.value.strip() + ean = self.getExpectedAttrNames() + if ((ean != None) & (self.attrs != None)): + present = ImmutableSet(self.attrs.getNames()) + unexpected = present.difference(ean) + for u in unexpected: + from logging import UnexpectedAttribute + self.log(UnexpectedAttribute({"attribute":u, "element":self.name})) self.validate() if self.isValid and self.name: from validators import ValidElement Index: src/feedvalidator/channel.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/channel.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 channel.py --- src/feedvalidator/channel.py 3 Feb 2004 17:33:15 -0000 1.1.1.1 +++ src/feedvalidator/channel.py 12 Feb 2004 17:25:03 -0000 @@ -9,11 +9,16 @@ from base import validatorBase from logging import * from validators import * +from sets import ImmutableSet # # channel element. # class channel(validatorBase): + def getExpectedAttrNames(self): + return ImmutableSet([(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'about'), + (u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'about')]) + def validate(self): if not "description" in self.children: self.log(MissingDescription({"parent":self.name,"element":"description"})) @@ -60,7 +65,7 @@ return eater() def do_category(self): - return text() + return category() def do_cloud(self): return cloud() @@ -204,8 +209,15 @@ class blink(validatorBase): def validate(self): self.log(NoBlink({})) - + +class category(text): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'domain')]) + class cloud(validatorBase): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'domain'), (None, u'path'), (None, u'registerProcedure'), + (None, u'protocol'), (None, u'port')]) def prevalidate(self): if (None, 'domain') not in self.attrs.getNames(): self.log(MissingAttribute({"parent":self.parent.name, "element":self.name, "attr":"domain"})) @@ -242,8 +254,13 @@ class ttl(positiveInteger): pass -class admin_generatorAgent(rdfResourceURI): pass -class admin_errorReportsTo(rdfResourceURI): pass +class admin_generatorAgent(rdfResourceURI): + def getExpectedAttrNames(self): + return ImmutableSet([(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'resource')]) + +class admin_errorReportsTo(rdfResourceURI): + def getExpectedAttrNames(self): + return ImmutableSet([(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'resource')]) class sy_updateFrequency(positiveInteger): pass Index: src/feedvalidator/generator.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/generator.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 generator.py --- src/feedvalidator/generator.py 3 Feb 2004 17:33:15 -0000 1.1.1.1 +++ src/feedvalidator/generator.py 12 Feb 2004 17:25:03 -0000 @@ -8,11 +8,15 @@ from base import validatorBase from validators import * +from sets import ImmutableSet # # Atom generator element # class generator(rfc2396): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'url')]) + def validate(self): if self.attrs.has_key((None, "url")): self.value = self.attrs.getValue((None, "url")) Index: src/feedvalidator/item.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/item.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 item.py --- src/feedvalidator/item.py 3 Feb 2004 17:33:16 -0000 1.1.1.1 +++ src/feedvalidator/item.py 12 Feb 2004 17:25:03 -0000 @@ -9,6 +9,7 @@ from base import validatorBase from validators import * from logging import * +from sets import ImmutableSet # # item element. @@ -57,7 +58,7 @@ if "dc_subject" in self.children: self.log(DuplicateItemSemantics({"core":"category", "ext":"dc:subject"})) self.log(UseDCSubject({"core":"category", "ext":"dc:subject"})) - return text() + return category() def do_dc_subject(self): if "category" in self.children: @@ -104,7 +105,13 @@ def do_xhtml_body(self): return htmlEater(self,'xhtml:body') +class category(text): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'domain')]) + class source(text, httpURLMixin): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'url')]) def prevalidate(self): try: self.validateHttpURL(None, 'url') @@ -141,6 +148,9 @@ return validatorBase.prevalidate(self) class guid(rfc2396, noduplicates): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'isPermaLink')]) + def validate(self): isPermalink = 1 try: @@ -158,7 +168,9 @@ self.log(ValidHttpGUID({"parent":self.parent.name, "element":self.name})) return noduplicates.validate(self) -class annotate_reference(rdfResourceURI): pass +class annotate_reference(rdfResourceURI): + def getExpectedAttrNames(self): + return ImmutableSet([(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', u'resource')]) __history__ = """ $Log: item.py,v $ Index: src/feedvalidator/link.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/link.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 link.py --- src/feedvalidator/link.py 3 Feb 2004 17:33:16 -0000 1.1.1.1 +++ src/feedvalidator/link.py 12 Feb 2004 17:25:03 -0000 @@ -8,11 +8,15 @@ from base import validatorBase from validators import * +from sets import ImmutableSet # # Atom link element # class link(nonblank,rfc2396): + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'type'), (None, u'title'), (None, u'rel'), (None, u'href')]) + def prevalidate(self): self.type = "" self.rel = "" Index: src/feedvalidator/logging.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/logging.py,v retrieving revision 1.6 diff -u -r1.6 logging.py --- src/feedvalidator/logging.py 7 Feb 2004 14:23:19 -0000 1.6 +++ src/feedvalidator/logging.py 12 Feb 2004 17:25:03 -0000 @@ -36,6 +36,7 @@ class MissingNamespace(SAXError): pass class NoBlink(UndefinedElement): pass class MissingAttribute(Error): pass +class UnexpectedAttribute(Error): pass class DuplicateElement(Error): pass class NotEnoughHoursInTheDay(Error): pass class EightDaysAWeek(Error): pass Index: src/feedvalidator/rss.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/rss.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 rss.py --- src/feedvalidator/rss.py 3 Feb 2004 17:33:16 -0000 1.1.1.1 +++ src/feedvalidator/rss.py 12 Feb 2004 17:25:03 -0000 @@ -9,6 +9,7 @@ from base import validatorBase from logging import * from validators import noduplicates +from sets import ImmutableSet # # Rss element. The only valid child element is "channel" @@ -17,6 +18,9 @@ def do_channel(self): from channel import channel return channel(), noduplicates() + + def getExpectedAttrNames(self): + return ImmutableSet([(None, u'version')]) def prevalidate(self): self.setFeedType(TYPE_RSS2) # could be anything in the 0.9x family, don't really care Index: src/feedvalidator/validators.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/validators.py,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 validators.py --- src/feedvalidator/validators.py 3 Feb 2004 17:33:17 -0000 1.1.1.1 +++ src/feedvalidator/validators.py 12 Feb 2004 17:25:03 -0000 @@ -9,6 +9,7 @@ from base import validatorBase from logging import * import re +from sets import Set,ImmutableSet rdfNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" @@ -63,6 +64,8 @@ ('foaf', 'name'), ('rdfs', 'seeAlso')) class text(validatorBase): + def getExpectedAttrNames(self): + return ImmutableSet() def startElementNS(self, name, qname, attrs): from base import namespaces ns = namespaces.get(qname, '') @@ -89,6 +92,8 @@ class noduplicates(validatorBase): def startElementNS(self, name, qname, attrs): pass + def getExpectedAttrNames(self): + return None def prevalidate(self): if self.name in self.parent.children: self.log(DuplicateElement({"parent":self.parent.name, "element":self.name})) @@ -377,6 +382,8 @@ nonblank.__init__(self) if not name+'s' in self.scope.__dict__: self.scope.__dict__[name+'s']=[] + def getExpectedAttrNames(self): + return None def validate(self): nonblank.validate(self) list=self.scope.__dict__[self.name+'s'] Index: src/feedvalidator/i18n/en.py =================================================================== RCS file: /cvsroot/feedvalidator/feedvalidator/src/feedvalidator/i18n/en.py,v retrieving revision 1.5 diff -u -r1.5 en.py --- src/feedvalidator/i18n/en.py 7 Feb 2004 14:23:19 -0000 1.5 +++ src/feedvalidator/i18n/en.py 12 Feb 2004 17:25:03 -0000 @@ -23,6 +23,7 @@ MissingOptionalElement: "%(parent)s should contain a %(element)s element", MissingRecommendedElement: "%(parent)s should contain a %(element)s element", MissingAttribute: "Missing %(element)s attribute: %(attr)s", + UnexpectedAttribute: "Unexpected %(attribute)s attribute on %(element)s element", NoBlink: "There is no blink element in RSS; use blogChannel:blink instead", InvalidValue: "Invalid value for %(element)s: \"%(value)s\"", InvalidWidth: "%(element)s must be between 1 and 144", --- /dev/null 2004-02-07 08:57:11.000000000 +0000 +++ docs/warning/UnexpectedAttribute.html 2004-02-12 16:42:14.000000000 +0000 @@ -0,0 +1,78 @@ + + + + +Unknown attributes should not appear in a feed + + + + + + + + +
+

Message

+
+

The elements in a feed should not have non-standard attributes

+
+

Explanation

+ +
+

Your feed contains elements with attributes that are not defined in the +relevant specifications. Perhaps this is a typo (remember that XML is +case-sensitive; for example, isPermalink and +isPermaLink have no relation to each other, +and only the latter has any meaning in the RSS 2.0 standard).

+ +

If you are trying to extend RSS, a new element in its own namespace is +likely to be more flexible, and less liable to cause interoperability +problems.

+
+ +

Solution

+
+

Correct the attributes, or move the information into a namespaced +element.

+
+

Not clear? Disagree?

+
+

Let us know on the feedvalidator-users discussion list! +

+ +
+
+ + +
+ +
+
Copyright © 2002-3 Mark Pilgrim and Sam Ruby
+
+ + + --- /dev/null 2004-02-07 08:57:11.000000000 +0000 +++ testcases/rss/must/valid_all_rss2_attributes.xml 2004-02-12 17:29:10.000000000 +0000 @@ -0,0 +1,29 @@ + + + + + + +All the valid RSS 2.0 attributes +http://purl.org/rss/2.0/ +foo +MSFT + + +An item with all item-level attributes +http://inessential.com/2002/09/01.php#a2 +Tomalak's Realm + +MSFT + + + --- /dev/null 2004-02-07 08:57:11.000000000 +0000 +++ testcases/rss/should/guid_value_isPermaLink_badAttributeCase.xml 2004-02-12 15:06:23.000000000 +0000 @@ -0,0 +1,24 @@ + + + + + + +Invalid GUID +http://purl.org/rss/2.0/ +foo + +http://www.example.com/ + + +