arabica/include/XSLT/impl/handler/xslt_value_validation.hpp
2012-11-21 06:59:40 +00:00

311 lines
11 KiB
C++

#ifndef ARABICA_XSLT_VALUE_VALIDATION_HPP
#define ARABICA_XSLT_VALUE_VALIDATION_HPP
namespace Arabica
{
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 string_type& v1, const string_type& v2, const string_type& v3)
{
allowed_.insert(v1);
allowed_.insert(v2);
allowed_.insert(v3);
} // 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>
AllowedValues<string_type> makeAllowedValues(const string_type& a1, const string_type& a2)
{
return AllowedValues<string_type>(a1, a2);
} // makeAllowedValues
template<class string_type>
AllowedValues<string_type> makeAllowedValues(const string_type& a1, const string_type& a2, const string_type& a3)
{
return AllowedValues<string_type>(a1, a2, a3);
} // makeAllowedValues
template<class string_type, class string_adaptor>
class AttributeValidator
{
public:
AttributeValidator() :
required_(false),
has_def_(false)
{
} // AttributeValidator
bool mandatory() const { return required_; }
bool has_default() const { return has_def_; }
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),
has_def_(false)
{
} // AttributeValidator
AttributeValidator(bool required, const string_type& def) :
required_(required),
def_(def),
has_def_(true)
{
} // AttributeValidator
AttributeValidator(bool required, const string_type& def, const AllowedValues<string_type> allowed) :
required_(required),
def_(def),
has_def_(true),
allowed_(allowed)
{
} // AttributeValidator
bool required_;
bool has_def_;
string_type def_;
AllowedValues<string_type> allowed_;
AttributeValidator& operator=(const AttributeValidator& rhs)
{
required_ = rhs.required_;
has_def_ = rhs.has_def_;
def_ = rhs.def_;
allowed_ = rhs.allowed_;
return *this;
} // operator=
friend class AttributeValidators<string_type, string_adaptor>;
friend class AttributeValidatorsBuilder<string_type, string_adaptor>;
}; // class AttributeValidator
template<class string_type, class string_adaptor>
class AttributeValidators
{
typedef StylesheetConstant<string_type, string_adaptor> SC;
public:
static AttributeValidatorsBuilder<string_type, string_adaptor> rule(const string_type& name, bool required);
static AttributeValidatorsBuilder<string_type, string_adaptor> rule(const string_type& name,
bool required,
const string_type& def);
static AttributeValidatorsBuilder<string_type, string_adaptor> rule(const string_type& name,
bool required,
const string_type& def,
const AllowedValues<string_type>& allowed);
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()) && (string_adaptor::empty(atts.getValue(name))))
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, const AttributeValidator<string_type, string_adaptor>& av)
{
rules_[name] = av;
} // put
AttributeValidators() { }
typedef std::map<string_type, AttributeValidator<string_type, string_adaptor> > ValidatorMap;
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 AttributeValidators<string_type, string_adaptor>&() { return validators_; }
AttributeValidatorsBuilder& rule(const string_type& name, bool required)
{
validators_.put(name, AttributeValidator<string_type, string_adaptor>(required));
return *this;
} // rule
AttributeValidatorsBuilder& rule(const string_type& name, bool required, const string_type& def)
{
validators_.put(name, AttributeValidator<string_type, string_adaptor>(required, def));
return *this;
} // rule
AttributeValidatorsBuilder& rule(const string_type& name, bool required, const string_type& def, const AllowedValues<string_type>& av)
{
validators_.put(name, AttributeValidator<string_type, string_adaptor>(required, def, av));
return *this;
} // rule
private:
AttributeValidatorsBuilder() { }
AttributeValidatorsBuilder(const AttributeValidatorsBuilder& rhs) :
validators_(rhs.validators_)
{
} // AttributeValidatorsBuilder
AttributeValidators<string_type, string_adaptor> validators_;
friend class AttributeValidators<string_type, string_adaptor>;
}; // class AttributeValidatorsBuilder
template<class string_type, class string_adaptor>
AttributeValidatorsBuilder<string_type, string_adaptor>
AttributeValidators<string_type, string_adaptor>::rule(const string_type& name, bool required)
{
AttributeValidatorsBuilder<string_type, string_adaptor> builder;
builder.rule(name, required);
return builder;
} // AttributeValidator::rule
template<class string_type, class string_adaptor>
AttributeValidatorsBuilder<string_type, string_adaptor>
AttributeValidators<string_type, string_adaptor>::rule(const string_type& name,
bool required,
const string_type& def)
{
AttributeValidatorsBuilder<string_type, string_adaptor> builder;
builder.rule(name, required, def);
return builder;
} // AttributeValidator::rule
template<class string_type, class string_adaptor>
AttributeValidatorsBuilder<string_type, string_adaptor>
AttributeValidators<string_type, string_adaptor>::rule(const string_type& name,
bool required,
const string_type& def,
const AllowedValues<string_type>& allowed)
{
AttributeValidatorsBuilder<string_type, string_adaptor> builder;
builder.rule(name, required, def, allowed);
return builder;
} // AttributeValidator::rule
template<class string_type, class string_adaptor>
void verifyNoCharacterData(const string_type& ch,
const string_type& name)
{
for(typename string_adaptor::const_iterator i = string_adaptor::begin(ch), e = string_adaptor::end(ch); i != e; ++i)
if(!Arabica::XML::is_space(*i))
throw SAX::SAXException(string_adaptor::asStdString(name) + " element can not contain character data.");
} // verifyNoCharacterContent
} // namespace XSLT
} // namespace Arabica
#endif