/**
   * @param existing
   * @param attributeItems
   * @return
   */
  protected SwordValidationInfo validate(
      ArrayList<SwordValidationInfo> existing,
      ArrayList<SwordValidationInfo> attributeItems,
      Properties validationContext) {
    boolean validateAll = (existing == null);

    SwordValidationInfo result = new SwordValidationInfo(xmlName);
    result.setContentDescription(content);

    // item specific rules
    if (content == null) {
      result.addValidationInfo(
          new SwordValidationInfo(
              xmlName, "Missing content for element", SwordValidationInfoType.WARNING));
    }

    if (validateAll) {
      SwordValidationInfo info =
          new SwordValidationInfo(
              xmlName, new XmlName(xmlName.getPrefix(), ATTRIBUTE_TYPE, xmlName.getNamespace()));
      info.setContentDescription(type.toString());
      result.addAttributeValidationInfo(info);
    }

    result.addUnmarshallValidationInfo(existing, attributeItems);
    return result;
  }
  /**
   * @param text
   * @param validate
   * @return
   * @throws org.purl.sword.base.UnmarshallException
   */
  public SwordValidationInfo unmarshall(Element text, Properties validationProperties)
      throws UnmarshallException {
    if (!isInstanceOf(text, xmlName)) {
      return handleIncorrectElement(text, validationProperties);
    }

    ArrayList<SwordValidationInfo> validationItems = new ArrayList<SwordValidationInfo>();
    ArrayList<SwordValidationInfo> attributeItems = new ArrayList<SwordValidationInfo>();

    try {
      initialise();

      // get the attributes
      int attributeCount = text.getAttributeCount();
      Attribute attribute = null;
      for (int i = 0; i < attributeCount; i++) {
        attribute = text.getAttribute(i);
        if (ATTRIBUTE_TYPE.equals(attribute.getQualifiedName())) {
          boolean success = true;
          String value = attribute.getValue();
          if (ContentType.TEXT.toString().equals(value)) {
            type = ContentType.TEXT;
          } else if (ContentType.HTML.toString().equals(value)) {
            type = ContentType.HTML;
          } else if (ContentType.XHTML.toString().equals(value)) {
            type = ContentType.XHTML;
          } else {
            log.error("Unable to parse extract type in " + getQualifiedName());
            SwordValidationInfo info =
                new SwordValidationInfo(
                    xmlName,
                    new XmlName(attribute),
                    "Invalid content type has been specified",
                    SwordValidationInfoType.ERROR);
            info.setContentDescription(value);
            attributeItems.add(info);
            success = false;
          }

          if (success) {
            SwordValidationInfo info = new SwordValidationInfo(xmlName, new XmlName(attribute));
            info.setContentDescription(type.toString());
            attributeItems.add(info);
          }
        } else {
          SwordValidationInfo info =
              new SwordValidationInfo(
                  xmlName,
                  new XmlName(attribute),
                  SwordValidationInfo.UNKNOWN_ATTRIBUTE,
                  SwordValidationInfoType.INFO);
          info.setContentDescription(attribute.getValue());
          attributeItems.add(info);
        }
      }

      // retrieve all of the sub-elements
      int length = text.getChildCount();
      if (length > 0) {
        content = unmarshallString(text);
      }

    } catch (Exception ex) {
      log.error("Unable to parse an element in " + getQualifiedName() + ": " + ex.getMessage());
      throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex);
    }

    SwordValidationInfo result = null;
    if (validationProperties != null) {
      result = validate(validationItems, attributeItems, validationProperties);
    }
    return result;
  }