Got the new attribute validation going

now to plug it in everywhere
This commit is contained in:
Jez Higgins 2012-11-15 19:38:48 +00:00
parent 47383b55b9
commit 5043f5bd4d
3 changed files with 165 additions and 15 deletions

View file

@ -9,16 +9,80 @@ namespace XSLT
template<class string_type, class string_adaptor> class AttributeValidatorsBuilder; template<class string_type, class string_adaptor> class AttributeValidatorsBuilder;
template<class string_type, class string_adaptor> class AttributeValidators; template<class string_type, class string_adaptor> class AttributeValidators;
template<class string_type>
class AllowedValues
{
public:
AllowedValues()
{
} // AllowedValues
AllowedValues(const string_type& v1, const string_type& v2)
{
allowed_.insert(v1);
allowed_.insert(v2);
} // AllowedValues
AllowedValues(const AllowedValues& rhs) :
allowed_(rhs.allowed_)
{
} // AllowedValues
bool is_allowed(const string_type& v) const
{
if(allowed_.size() == 0)
return true;
return allowed_.find(v) != allowed_.end();
} // is_allowed
AllowedValues& operator=(const AllowedValues& rhs)
{
allowed_ = rhs.allowed_;
return *this;
} // operator=
private:
std::set<string_type> allowed_;
}; // AllowedValues
template<class string_type, class string_adaptor> template<class string_type, class string_adaptor>
class AttributeValidator class AttributeValidator
{ {
public:
AttributeValidator() :
required_(false)
{
} // AttributeValidator
bool mandatory() const { return required_; }
bool has_default() const { return !def_.empty(); }
const string_type& default_value() const { return def_; }
bool is_allowed(const string_type& v) const { return allowed_.is_allowed(v); }
private: private:
explicit AttributeValidator(bool required) : explicit AttributeValidator(bool required) :
required_(required) required_(required)
{ {
} // AttributeValidator } // AttributeValidator
AttributeValidator(bool required, const string_type& def, const AllowedValues<string_type> allowed) :
required_(required),
def_(def),
allowed_(allowed)
{
} // AttributeValidator
bool required_; bool required_;
string_type def_;
AllowedValues<string_type> allowed_;
AttributeValidator& operator=(const AttributeValidator& rhs)
{
required_ = rhs.required_;
def_ = rhs.def_;
allowed_ = rhs.allowed_;
return *this;
} // operator=
friend class AttributeValidators<string_type, string_adaptor>; friend class AttributeValidators<string_type, string_adaptor>;
}; // class AttributeValidator }; // class AttributeValidator
@ -26,28 +90,113 @@ private:
template<class string_type, class string_adaptor> template<class string_type, class string_adaptor>
class AttributeValidators class AttributeValidators
{ {
typedef StylesheetConstant<string_type, string_adaptor> SC;
public: public:
static AttributeValidatorsBuilder rule(const string_type& name, bool required); static AttributeValidatorsBuilder<string_type, string_adaptor> rule(const string_type& name, bool required);
std::map<string_type, string_type> gather(const string_type& parentElement,
const SAX::Attributes<string_type, string_adaptor>& atts) const
{
typedef StylesheetConstant<string_type, string_adaptor> SC;
std::map<string_type, string_type> results;
for(ValidatorMapIterator r = rules_.begin(); r != rules_.end(); ++r)
{
const string_type& name = r->first;
const AttributeValidator<string_type, string_adaptor>& av = r->second;
if((av.mandatory()) && (atts.getValue(name).empty()))
throw SAX::SAXException(string_adaptor::asStdString(parentElement) + ": Attribute " + string_adaptor::asStdString(name) + " must be specified");
if(av.has_default())
results[name] = av.default_value();
} // for ...
for(int a = 0; a < atts.getLength(); ++a)
{
const string_type& name = atts.getLocalName(a);
if(name == string_adaptor::empty_string())
continue; // namespace decl
const string_type& uri = atts.getURI(a);
const string_type& value = atts.getValue(a);
results[name] = value;
if(uri == string_adaptor::empty_string())
validateAttribute(parentElement, name, value);
else if(uri == SC::xml_uri)
validateXmlAttribute(parentElement, name, value); // special xml: attributes
} // for ...
return results;
} // gather
private: private:
void validateXmlAttribute(const string_type& parentElement,
const string_type& name,
const string_type& value) const
{
if(name == SC::space)
validateValues(parentElement, name, value, XMLSpaceValidator);
} // validateXmlAttribute
void validateAttribute(const string_type& parentElement,
const string_type& name,
const string_type& value) const
{
ValidatorMapIterator r = rules_.find(name);
if(r == rules_.end())
throw SAX::SAXException(string_adaptor::asStdString(parentElement) + ": Illegal attribute " + string_adaptor::asStdString(name));
validateValues(parentElement, name, value, r->second);
}
void validateValues(const string_type& parentElement,
const string_type& name,
const string_type& value,
const AttributeValidator<string_type, string_adaptor>& rule) const
{
if(rule.is_allowed(value))
return;
throw SAX::SAXException(string_adaptor::asStdString(value) +
" is not an allowed value for " +
string_adaptor::asStdString(parentElement) +
"/@ " +
string_adaptor::asStdString(name));
} // validateValues
void put(const string_type& name, bool required) void put(const string_type& name, bool required)
{ {
rules_[name] = AttributeValidate(required); rules_[name] = AttributeValidator<string_type, string_adaptor>(required);
} // put } // put
AttributeValidators() { } AttributeValidators() { }
typedef std::map<string_type, AttributeValidator<string_type, string_adaptor> > ValidatorMap; typedef std::map<string_type, AttributeValidator<string_type, string_adaptor> > ValidatorMap;
typedef typename std::map<string_type, AttributeValidator<string_type, string_adaptor> >::const_iterator ValidatorMapIterator; typedef typename ValidatorMap::const_iterator ValidatorMapIterator;
ValidatorMap rules_; ValidatorMap rules_;
};
static const AttributeValidator<string_type, string_adaptor> XMLSpaceValidator;
friend class AttributeValidatorsBuilder<string_type, string_adaptor>;
}; // class AttributeValidators
template<class string_type, class string_adaptor>
const AttributeValidator<string_type, string_adaptor>
AttributeValidators<string_type, string_adaptor>::XMLSpaceValidator(false,
string_adaptor::empty_string(),
AllowedValues<string_type>(string_adaptor::construct_from_utf8("default"),
string_adaptor::construct_from_utf8("preserve")));
template<class string_type, class string_adaptor> template<class string_type, class string_adaptor>
class AttributeValidatorsBuilder class AttributeValidatorsBuilder
{ {
public: public:
operator AttributeValidator<string_type, string_adaptor>&() { return validators_; } operator AttributeValidators<string_type, string_adaptor>&() { return validators_; }
AttributeValidatorsBuilder& rule(const string_type& name, bool required) AttributeValidatorsBuilder& rule(const string_type& name, bool required)
{ {
@ -58,11 +207,11 @@ public:
private: private:
AttributeValidatorsBuilder() { } AttributeValidatorsBuilder() { }
AttributeValidatorsBuilder(const AttributeValidatorsBuilder& rhs) : AttributeValidatorsBuilder(const AttributeValidatorsBuilder& rhs) :
validators_(validators) validators_(rhs.validators_)
{ {
} // AttributeValidatorsBuilder } // AttributeValidatorsBuilder
AttributeValidator<string_type, string_adaptor> validators_; AttributeValidators<string_type, string_adaptor> validators_;
friend class AttributeValidators<string_type, string_adaptor>; friend class AttributeValidators<string_type, string_adaptor>;
}; // class AttributeValidatorsBuilder }; // class AttributeValidatorsBuilder

View file

@ -25,6 +25,7 @@ template<class string_type, class string_adaptor>
class StylesheetHandler : public SAX::DefaultHandler<string_type, string_adaptor> class StylesheetHandler : public SAX::DefaultHandler<string_type, string_adaptor>
{ {
typedef StylesheetConstant<string_type, string_adaptor> SC; typedef StylesheetConstant<string_type, string_adaptor> SC;
typedef AttributeValidators<string_type, string_adaptor> AV;
public: public:
typedef string_type stringT; typedef string_type stringT;
typedef string_adaptor string_adaptorT; typedef string_adaptor string_adaptorT;
@ -94,12 +95,12 @@ private:
if(localName != SC::stylesheet && localName != SC::transform) if(localName != SC::stylesheet && localName != SC::transform)
throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'."); throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'.");
static const ValueRule<string_type> rules[] = { { SC::version, true }, static const AV rules = AV::rule(SC::version, true)
{ SC::extension_element_prefixes, false }, .rule(SC::extension_element_prefixes, false)
{ SC::exclude_result_prefixes, false }, .rule(SC::exclude_result_prefixes, false)
{ SC::id, false }, .rule(SC::id, false);
{ string_adaptor::empty_string(), false } };
std::map<string_type, string_type> attributes = gatherAttributes(qName, atts, rules); std::map<string_type, string_type> attributes = rules.gather(qName, atts);
if(attributes[SC::version] != SC::Version) if(attributes[SC::version] != SC::Version)
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer."); throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
if(!attributes[SC::extension_element_prefixes].empty()) if(!attributes[SC::extension_element_prefixes].empty())

View file

@ -51,8 +51,8 @@ int main(int argc, const char* argv[])
Loader loader; Loader loader;
add_tests(runner, loader, tests_to_run, xalan_tests); //add_tests(runner, loader, tests_to_run, xalan_tests);
add_tests(runner, loader, tests_to_run, msft_tests); //add_tests(runner, loader, tests_to_run, msft_tests);
add_arabica_tests(runner, loader, tests_to_run, arabica_tests); add_arabica_tests(runner, loader, tests_to_run, arabica_tests);
runner.run(argc, argv); runner.run(argc, argv);