diff --git a/includes/XtoolsBlueprintArray.inc b/includes/XtoolsBlueprintArray.inc
index f639a1f..6d8ee66 100644
--- a/includes/XtoolsBlueprintArray.inc
+++ b/includes/XtoolsBlueprintArray.inc
@@ -3,8 +3,17 @@
 class XtoolsBlueprintArray extends XtoolsBlueprintOr {
 
   /**
+   * An array of XtoolsBlueprintChildElement objects. Keys and values should
+   * match the keys and values of XtoolsBlueprintArray::validate()'s $value
+   * parameter.
+   *
+   * @var array
+   */
+  public $allowed_blueprints_associative = array();
+
+  /**
    * Either "string" or "integer", in case the array keys need to be of a
-   * certain type.
+   * certain type, or NULL if the keys can be of either type.
    *
    * @var string
    */
@@ -12,13 +21,34 @@ class XtoolsBlueprintArray extends XtoolsBlueprintOr {
 
   public $type = 'array';
 
+  /**
+   * Constructor.
+   *
+   * @param array $allowed_blueprints
+   *   An array with two items:
+   *   - associative: an array containing XtoolsBlueprintChildElement objects.
+   *     If the validated value has any keys in common with this array, the
+   *     corresponding will be validated using these blueprints.
+   *   - nonassociative: an array containing XtoolsBlueprint objects. If the
+   *     validated value contains items of which the keys are not present in
+   *     XtoolsBlueprintArray::allowed_blueprints_associative, then they are
+   *     validated against these blueprints.
+   * @param boolean|null $key_type
+   *   Either "string" or "integer" to indicate that array keys should be of
+   *   this type, or NULL so skip key validation.
+   */
   function __construct(array $allowed_blueprints = array(), $key_type = NULL) {
-    $this->allowed_blueprints = $allowed_blueprints;
+    $allowed_blueprints += array(
+      'associative' => array(),
+      'nonassociative' => array(),
+    );
+    $this->allowed_blueprints_associative = $allowed_blueprints['associative'];
+    $this->allowed_blueprints = $allowed_blueprints['nonassociative'];
     $this->key_type = $key_type;
   }
 
   /**
-   * Implements XtoolsBlueprint::match().
+   * Implements XtoolsBlueprint::validate().
    *
    * @param array $value
    */
@@ -32,9 +62,20 @@ class XtoolsBlueprintArray extends XtoolsBlueprintOr {
         }
       }
 
-      // Validate array elements.
+      // Validate associative array elements.
+      foreach ($this->allowed_blueprints_associative as $key => $array_element) {
+        $element_path = $path . (is_string($key) ? "['$key']" : "[$key]");
+        if ($array_element->required) {
+          $asserts[] = new XtoolsAssert(isset($value[$key]), "required array element $element_path is set.");
+        }
+        if (isset($value[$key])) {
+          $array_element->validate($value[$key], $asserts, $element_path);
+        }
+      }
+
+      // Validate non-associative array elements.
       if ($this->allowed_blueprints) {
-        foreach ($value as $key => $element) {
+        foreach (array_diff_keys($value, $this->allowed_blueprints_associative) as $key => $element) {
           $element_path = $path . (is_string($key) ? "['$key']" : "[$key]");
           parent::validate($element, $asserts, $element_path);
         }
