/**
   * Handle attribute node during validation.
   *
   * @param receivedElement
   * @param receivedAttribute
   * @param sourceElement
   * @param validationContext
   */
  private void doAttribute(
      Node receivedElement,
      Node receivedAttribute,
      Node sourceElement,
      XmlMessageValidationContext validationContext,
      NamespaceContext namespaceContext,
      TestContext context) {
    if (receivedAttribute.getNodeName().startsWith(XMLConstants.XMLNS_ATTRIBUTE)) {
      return;
    }

    String receivedAttributeName = receivedAttribute.getLocalName();

    if (log.isDebugEnabled()) {
      log.debug(
          "Validating attribute: "
              + receivedAttributeName
              + " ("
              + receivedAttribute.getNamespaceURI()
              + ")");
    }

    NamedNodeMap sourceAttributes = sourceElement.getAttributes();
    Node sourceAttribute =
        sourceAttributes.getNamedItemNS(receivedAttribute.getNamespaceURI(), receivedAttributeName);

    Assert.isTrue(
        sourceAttribute != null,
        "Attribute validation failed for element '"
            + receivedElement.getLocalName()
            + "', unknown attribute "
            + receivedAttributeName
            + " ("
            + receivedAttribute.getNamespaceURI()
            + ")");

    if (XmlValidationUtils.isAttributeIgnored(
        receivedElement,
        receivedAttribute,
        sourceAttribute,
        validationContext.getIgnoreExpressions(),
        namespaceContext)) {
      return;
    }

    String receivedValue = receivedAttribute.getNodeValue();
    String sourceValue = sourceAttribute.getNodeValue();
    if (isValidationMatcherExpression(sourceAttribute)) {
      ValidationMatcherUtils.resolveValidationMatcher(
          sourceAttribute.getNodeName(),
          receivedAttribute.getNodeValue().trim(),
          sourceAttribute.getNodeValue().trim(),
          context);
    } else if (receivedValue.contains(":") && sourceValue.contains(":")) {
      doNamespaceQualifiedAttributeValidation(
          receivedElement, receivedAttribute, sourceElement, sourceAttribute);
    } else {
      Assert.isTrue(
          receivedValue.equals(sourceValue),
          ValidationUtils.buildValueMismatchErrorMessage(
              "Values not equal for attribute '" + receivedAttributeName + "'",
              sourceValue,
              receivedValue));
    }

    if (log.isDebugEnabled()) {
      log.debug("Attribute '" + receivedAttributeName + "'='" + receivedValue + "': OK");
    }
  }
  /**
   * Handle element node.
   *
   * @param received
   * @param source
   * @param validationContext
   */
  private void doElement(
      Node received,
      Node source,
      XmlMessageValidationContext validationContext,
      NamespaceContext namespaceContext,
      TestContext context) {

    doElementNameValidation(received, source);

    doElementNamespaceValidation(received, source);

    // check if element is ignored either by xpath or by ignore placeholder in source message
    if (XmlValidationUtils.isElementIgnored(
        source, received, validationContext.getIgnoreExpressions(), namespaceContext)) {
      return;
    }

    // work on attributes
    if (log.isDebugEnabled()) {
      log.debug("Validating attributes for element: " + received.getLocalName());
    }
    NamedNodeMap receivedAttr = received.getAttributes();
    NamedNodeMap sourceAttr = source.getAttributes();

    Assert.isTrue(
        countAttributes(receivedAttr) == countAttributes(sourceAttr),
        ValidationUtils.buildValueMismatchErrorMessage(
            "Number of attributes not equal for element '" + received.getLocalName() + "'",
            countAttributes(sourceAttr),
            countAttributes(receivedAttr)));

    for (int i = 0; i < receivedAttr.getLength(); i++) {
      doAttribute(
          received, receivedAttr.item(i), source, validationContext, namespaceContext, context);
    }

    // check if validation matcher on element is specified
    if (isValidationMatcherExpression(source)) {
      ValidationMatcherUtils.resolveValidationMatcher(
          source.getNodeName(),
          received.getFirstChild().getNodeValue().trim(),
          source.getFirstChild().getNodeValue().trim(),
          context);
      return;
    }

    // work on child nodes
    NodeList receivedChilds = received.getChildNodes();
    NodeList sourceChilds = source.getChildNodes();

    Assert.isTrue(
        receivedChilds.getLength() == sourceChilds.getLength(),
        ValidationUtils.buildValueMismatchErrorMessage(
            "Number of child elements not equal for element '" + received.getLocalName() + "'",
            sourceChilds.getLength(),
            receivedChilds.getLength()));

    for (int i = 0; i < receivedChilds.getLength(); i++) {
      this.validateXmlTree(
          receivedChilds.item(i),
          sourceChilds.item(i),
          validationContext,
          namespaceContext,
          context);
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "Validation successful for element: "
              + received.getLocalName()
              + " ("
              + received.getNamespaceURI()
              + ")");
    }
  }