mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-25 21:58:21 +01:00
Got the new attribute validation going
now to plug it in everywhere
This commit is contained in:
parent
47383b55b9
commit
5043f5bd4d
3 changed files with 165 additions and 15 deletions
|
@ -9,16 +9,80 @@ namespace XSLT
|
|||
template<class string_type, class string_adaptor> class AttributeValidatorsBuilder;
|
||||
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>
|
||||
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:
|
||||
explicit AttributeValidator(bool required) :
|
||||
required_(required)
|
||||
{
|
||||
} // AttributeValidator
|
||||
|
||||
AttributeValidator(bool required, const string_type& def, const AllowedValues<string_type> allowed) :
|
||||
required_(required),
|
||||
def_(def),
|
||||
allowed_(allowed)
|
||||
{
|
||||
} // AttributeValidator
|
||||
|
||||
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>;
|
||||
}; // class AttributeValidator
|
||||
|
@ -26,28 +90,113 @@ private:
|
|||
template<class string_type, class string_adaptor>
|
||||
class AttributeValidators
|
||||
{
|
||||
typedef StylesheetConstant<string_type, string_adaptor> SC;
|
||||
|
||||
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:
|
||||
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)
|
||||
{
|
||||
rules_[name] = AttributeValidate(required);
|
||||
rules_[name] = AttributeValidator<string_type, string_adaptor>(required);
|
||||
} // put
|
||||
|
||||
AttributeValidators() { }
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
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>
|
||||
class AttributeValidatorsBuilder
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -58,11 +207,11 @@ public:
|
|||
private:
|
||||
AttributeValidatorsBuilder() { }
|
||||
AttributeValidatorsBuilder(const AttributeValidatorsBuilder& rhs) :
|
||||
validators_(validators)
|
||||
validators_(rhs.validators_)
|
||||
{
|
||||
} // AttributeValidatorsBuilder
|
||||
|
||||
AttributeValidator<string_type, string_adaptor> validators_;
|
||||
AttributeValidators<string_type, string_adaptor> validators_;
|
||||
|
||||
friend class AttributeValidators<string_type, string_adaptor>;
|
||||
}; // class AttributeValidatorsBuilder
|
||||
|
|
|
@ -25,6 +25,7 @@ template<class string_type, class string_adaptor>
|
|||
class StylesheetHandler : public SAX::DefaultHandler<string_type, string_adaptor>
|
||||
{
|
||||
typedef StylesheetConstant<string_type, string_adaptor> SC;
|
||||
typedef AttributeValidators<string_type, string_adaptor> AV;
|
||||
public:
|
||||
typedef string_type stringT;
|
||||
typedef string_adaptor string_adaptorT;
|
||||
|
@ -94,12 +95,12 @@ private:
|
|||
if(localName != SC::stylesheet && localName != SC::transform)
|
||||
throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'.");
|
||||
|
||||
static const ValueRule<string_type> rules[] = { { SC::version, true },
|
||||
{ SC::extension_element_prefixes, false },
|
||||
{ SC::exclude_result_prefixes, false },
|
||||
{ SC::id, false },
|
||||
{ string_adaptor::empty_string(), false } };
|
||||
std::map<string_type, string_type> attributes = gatherAttributes(qName, atts, rules);
|
||||
static const AV rules = AV::rule(SC::version, true)
|
||||
.rule(SC::extension_element_prefixes, false)
|
||||
.rule(SC::exclude_result_prefixes, false)
|
||||
.rule(SC::id, false);
|
||||
|
||||
std::map<string_type, string_type> attributes = rules.gather(qName, atts);
|
||||
if(attributes[SC::version] != SC::Version)
|
||||
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
|
||||
if(!attributes[SC::extension_element_prefixes].empty())
|
||||
|
|
|
@ -51,8 +51,8 @@ int main(int argc, const char* argv[])
|
|||
|
||||
Loader loader;
|
||||
|
||||
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, xalan_tests);
|
||||
//add_tests(runner, loader, tests_to_run, msft_tests);
|
||||
add_arabica_tests(runner, loader, tests_to_run, arabica_tests);
|
||||
|
||||
runner.run(argc, argv);
|
||||
|
|
Loading…
Reference in a new issue