Schema.org Microdata validation plugin I am starting to write a plugin that is aiming to validate a piece of mark up against requirements of schema.org.

I was hoping if I could get some more tips on how to improve the structure of my code. Is this how you would go about this if you were to do it?

    $.fn.hasAttr = function(name) {  
       return this.attr(name) !== undefined;
    };

    $.fn.outerHTML = function(s) {
        return $(this).clone().wrap('&lt;div&gt;').parent().html();
    };

    $.fn.getOpeningTag = function (s) {
      return $(this).outerHTML().slice(0, $(this).outerHTML().indexOf("&gt;") + 1) 
    }


    $.fn.validateSchema = function(options) {

      var defaults = {
        // for a list of international postcode regex see: http://www.thalesjacobi.com/Regex_to_validate_postcodes
        // The one used in the example is from the UK
        localPostCodeFormat: new RegExp("^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) {0,1}[0-9][A-Za-z]{2})$"),
        utilities : {
            missAtrr : function (target, attrName) {
              if (!target.hasAttr(attrName)){
                 defaults.returnError(target, "The element " + target.getOpeningTag()  + " is missing the required attribute " + attrName);                          
              }
            },              
            isValidPostCode : function (target) {
              if (!defaults.localPostCodeFormat.test(target.text())) {
                defaults.returnError(target, target.getOpeningTag() + " does not have a valid post code");
              }

            }
        },
        returnError : function (target, errorMessage) {
          var errorContainer = $('&lt;span class="schemaError"&gt;&lt;/span&gt;');  
          target.before(errorContainer);
          errorContainer.css({
            'color' : 'red',
            'border': 'solid 1px red'
            }).text(errorMessage);
        } // more utils to be added
      };
      // Extend our default options with those provided.
      var opts = $.extend(defaults, options);

      var schemaElements = {
            postalAddress : $(this).find('[itemtype*=PostalAddress]'),
            itemProps : $(this).find("[itemprop]"),
            emptyProps : $(this).find("[itemprop='']"),
            postCode : $(this).find("[itemprop=postalCode]"),
            email : $(this).find("[itemprop=email]"),
            outofplaceChild : $(this).find("[itemscope]").siblings("[itemprop]")// more dom refs to be added
        }

      // validation stuff
      //
      // PostalAddress should have itemsscope
      if (schemaElements.postalAddress){
        defaults.utilities.missAtrr(schemaElements.postalAddress, "itemscope");
      }
      // No itemscope can be left empty
      if (schemaElements.emptyProps){
        $.each(schemaElements.emptyProps, function () {
            defaults.returnError($(this), $(this).getOpeningTag() + " can not be left without a value");    
        });             
      }
      // postcode should match the post code format of that country
      if (schemaElements.postCode){
        defaults.utilities.isValidPostCode(schemaElements.postCode);
      }
      // No itemprop can exist without having a itemscope parent
      if (schemaElements.outofplaceChild){
        $.each(schemaElements.outofplaceChild, function () {
            defaults.returnError($(this), $(this).getOpeningTag() + " Does not have a itemscope parent");   
        });   
      }
      // more rules to be added
    };

    $(function(){
        $('body').validateSchema();     
    });
This will return false for attr in such an object {'attr': undefined}:

$.fn.hasAttr = function(name) {  
   return this.attr(name) !== undefined;
};


If this is not exactly what you want, have a look at related posts (one, two) and search for much more.



This (and similars) will always evaluate to true, if schemaElements object has the postalAddress key:

if (schemaElements.postalAddress){
    defaults.utilities.missAtrr(schemaElements.postalAddress, "itemscope");
}


here's an example session from Chrome developer console:

var rules = {'a': $('html').find('#idontexist')};
rules.a;
// []
if (rules.a) {console.log(true)} else {console.log(false)};
// true




Be consistent with ; at the end of the lines.