Viewing file: AttributeInfo.py (14.93 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Xml/Xslt/AttributeInfo.py,v 1.29 2005/03/19 00:12:16 jkloth Exp $ """ Classes that support validation and evaluation of attribute values in XSLT instruction elements
Copyright 2003 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
from Ft import TranslateMessage as _
import cStringIO, traceback
from Ft.Xml.XPath import Conversions from Ft.Xml.XPath import RuntimeException as XPathRuntimeException from Ft.Xml.XPath import parser _xpath_parser = parser.new()
from Ft.Xml.Xslt import XsltException, XsltRuntimeException, Error from Ft.Xml.Xslt import parser _xpattern_parser = parser.new() del parser
from Ft.Xml import XML_NAMESPACE, XMLNS_NAMESPACE, EMPTY_NAMESPACE from Ft.Xml.Lib.XmlString import IsQName, SplitQName
from AttributeValueTemplate import AttributeValueTemplate
class AttributeInfo:
display = 'unknown'
def __init__(self, required=0, default=None, description=''): self.required = required self.default = default self.description = description return
def __str__(self): return self.display
def prepare(self, element, value): if value is None: return self.default return value reprocess = prepare
def validate(self, validation): return 1
class _ConstantValue: def __init__(self, value): self.value = value
def isConstant(self): return 1
def evaluate(self, context): return self.value
def __repr__(self): return repr(self.value)
def __nonzero__(self): return self.value is not None
class Choice(AttributeInfo):
def __init__(self, values, required=0, default=None, description=''): AttributeInfo.__init__(self, required, default, description) self.values = values return
def prepare(self, element, value): if value is None: return self.default if value not in self.values: # check for a AttributeInfo instance allowed = filter(lambda v, t=type(self): type(v) is t, self.values) for info in allowed: try: allowed.prepare(element, value) return value except: pass # if we get here it is an error raise XsltException(Error.INVALID_ATTR_CHOICE, value, str(self)) return value reprocess = prepare
def __str__(self): return ' | '.join(map(lambda v: '"' + v + '"', self.values))
class Avt:
def __str__(self): return '{ %s }' % self.display
def prepare(self, element, value): if value is None: return _ConstantValue(self.reprocess(element, self.default)) elif '{' not in value and '}' not in value: return _ConstantValue(self.reprocess(element, value)) try: return AttributeValueTemplate(value, self, element) except SyntaxError, error: # an error from the XPath parser raise XsltException(Error.INVALID_AVT, value, element.baseUri, element.lineNumber, element.columnNumber, str(error)) except XsltException, error: raise XsltException(Error.INVALID_AVT, value, element.baseUri, element.lineNumber, element.columnNumber, error.args[0])
class ChoiceAvt(Avt, Choice):
def __str__(self): return '{ %s }' % Choice.__str__(self)
class AnyAvt(Avt, AttributeInfo): display = _('any avt')
class String(AttributeInfo): display = _('string')
class StringAvt(Avt, String): pass
class Char(AttributeInfo): """ A string value with a length of one """ display = _('char')
def prepare(self, element, value): if value is None: return self.default if len(value) > 1: raise XsltException(Error.INVALID_CHAR_ATTR, value) return value reprocess = prepare
class CharAvt(Avt, Char): pass
class Number(AttributeInfo): display = _('number')
def prepare(self, element, value): if value is None: return self.default try: return float(value or self.default) except: raise XsltException(Error.INVALID_NUMBER_ATTR, value) reprocess = prepare
class NumberAvt(Avt, Number): reprocess = Number.prepare
class UriReference(AttributeInfo): display = _('uri-reference')
def __init__(self, required=0, default=None, description='', isNsName=0): AttributeInfo.__init__(self, required, default, description) self._isNsName = isNsName
def prepare(self, element, value): if value is None: return self.default if self._isNsName and \ value == XML_NAMESPACE or value == XMLNS_NAMESPACE: raise XsltException(Error.INVALID_NS_URIREF_ATTR, value) return value reprocess = prepare
class UriReferenceAvt(Avt, UriReference): pass
class Id(AttributeInfo): display = _('id')
def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_ID_ATTR, value) return value reprocess = prepare
class IdAvt(Avt, Id): pass
class QName(AttributeInfo): display = _('qname')
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not IsQName(value): raise XsltException(Error.INVALID_QNAME_ATTR, value) prefix, local = SplitQName(value) if prefix: try: namespace = element.namespaces[prefix] except KeyError: raise XsltRuntimeException(Error.UNDEFINED_PREFIX, element, prefix) else: namespace = EMPTY_NAMESPACE return (namespace, local) reprocess = prepare
class QNameAvt(Avt, QName): pass
class RawQName(QName):
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not IsQName(value): raise XsltException(Error.INVALID_QNAME_ATTR, value) return SplitQName(value) reprocess = prepare
class RawQNameAvt(Avt, RawQName): pass
class NCName(AttributeInfo): display = _('ncname')
def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_NCNAME_ATTR, value) if ':' in value: raise XsltException(Error.INVALID_NCNAME_ATTR, value) return value reprocess = prepare
class NCNameAvt(Avt, NCName): pass
class Prefix(AttributeInfo): display = _('prefix')
def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_PREFIX_ATTR, value) if ':' in value: raise XsltException(Error.INVALID_PREFIX_ATTR, value) if value == '#default': value = None return value reprocess = prepare
class PrefixAvt(Avt, Prefix): pass
class NMToken(AttributeInfo): display = _('nmtoken')
def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_NMTOKEN_ATTR, value) return value reprocess = prepare
class NMTokenAvt(Avt, NMToken): pass
class QNameButNotNCName(AttributeInfo): display = _('qname-but-not-ncname')
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not value: raise XsltException(Error.QNAME_BUT_NOT_NCNAME, value)
try: index = value.index(':') except ValueError: raise XsltException(Error.QNAME_BUT_NOT_NCNAME, value) prefix, local = value[:index], value[index+1:] try: namespace = element.namespaces[prefix] except KeyError: raise XsltRuntimeException(Error.UNDEFINED_PREFIX, element, prefix) return (namespace, local) reprocess = prepare
class Token(AttributeInfo): """ An attribute whose value is used as an XPath NameTest """ display = _('token')
def prepare(self, element, value): # a 'token' is really an XPath NameTest; '*' | NCName ':' '*' | QName # From XPath 1.0 section 2.3: # if the QName does not have a prefix, then the namespace URI is null index = value.rfind(':') if index == -1: namespace = None local = value else: prefix = value[:index] local = value[index+1:] try: namespace = element.namespaces[prefix] except KeyError: raise XsltRuntimeException(Error.UNDEFINED_PREFIX, element, prefix) return (namespace, local) reprocess = prepare
class TokenAvt(Avt, Token): pass
class ExpressionWrapper:
def __init__(self, expression, element, original): self.expression = expression self.element = element self.original = original return
def __nonzero__(self): # True if self.expression is not None, which is always the case # otherwise this instance would not exist! return True
def __getattr__(self, attr): """Make this behave as if it was the expression object itself.""" return getattr(self.expression, attr)
# Provide the copy/pickle helpers so as to not get them from the # wrapped expression. def __getstate__(self): return (self.expression, self.element, self.original)
def __setstate__(self, state): self.expression, self.element, self.original = state return
def evaluate(self,context): try: return self.expression.evaluate(context) except XPathRuntimeException, e: import MessageSource e.message = MessageSource.EXPRESSION_POSITION_INFO % ( self.element.baseUri, self.element.lineNumber, self.element.columnNumber, self.original, str(e)) # By modifying the exception value directly, we do not need # to raise with that value, thus leaving the frame stack # intact (original traceback is displayed). raise except XsltRuntimeException, e: import MessageSource e.message = MessageSource.XSLT_EXPRESSION_POSITION_INFO % ( str(e), self.original) # By modifying the exception value directly, we do not need # to raise with that value, thus leaving the frame stack # intact (original traceback is displayed). raise except Exception, e: import MessageSource tb = cStringIO.StringIO() tb.write("Lower-level traceback:\n") traceback.print_exc(1000, tb) raise RuntimeError(MessageSource.EXPRESSION_POSITION_INFO % ( self.element.baseUri, self.element.lineNumber, self.element.columnNumber, self.original, tb.getvalue()))
class Expression(AttributeInfo): """ An attribute whose value is used as an XPath expression """ display = _('expression')
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default try: expression = _xpath_parser.parse(value) except SyntaxError, error: raise XsltException(Error.INVALID_EXPRESSION, value, element.baseUri, element.lineNumber, element.columnNumber, str(error)) return ExpressionWrapper(expression, element, value)
class NodeSetExpression(Expression): display = _('node-set-expression')
class StringExpression(Expression): display = _('string-expression')
class NumberExpression(Expression): display = _('number-expression')
class BooleanExpression(Expression): display = _('boolean-expression')
class Pattern(AttributeInfo): """ An attribute whose value is used as an XPattern expression """ display = _('pattern')
def prepare(self, element, value): if value is None: if self.default: value = self.default else: return None try: return _xpattern_parser.parse(value) except SyntaxError, error: raise XsltException(Error.INVALID_PATTERN, value, element.baseUri, element.lineNumber, element.columnNumber, str(error))
class Tokens(Token): """ A whitespace separated list of tokens (see Token for description of a token) """ display = _('tokens')
def prepare(self, element, value): if value is None: return [] tokens = [] for token in value.split(): prepared = Token.prepare(self, element, token) tokens.append(prepared) return tokens reprocess = prepare
class TokensAvt(Avt, Tokens): pass
class QNames(QName): """ A whitespace separated list of qnames (see QName for description of a qname) """ display = _('qnames')
def prepare(self, element, value): if value is None: return [] qnames = [] for qname in value.split(): prepared = QName.prepare(self, element, qname) qnames.append(prepared) return qnames reprocess = prepare
class QNamesAvt(Avt, QNames): pass
class Prefixes(Prefix): """ A whitespace separated list of prefixes (see Prefix for more information) """ display = _('prefixes')
def prepare(self, element, value): if value is None: return [] prefixes = [] for prefix in value.split(): prepared = Prefix.prepare(self, element, prefix) prefixes.append(prepared) return prefixes reprocess = prepare
class PrefixesAvt(Avt, Prefixes): pass
class YesNo(AttributeInfo):
display = '"yes" | "no"'
def prepare(self, element, value): if value is None: return self.default and self.default == 'yes' elif value not in ['yes', 'no']: raise XsltException(Error.INVALID_ATTR_CHOICE, value, str(self)) return value == 'yes' reprocess = prepare
class YesNoAvt(Avt, YesNo): pass
|