/**
   * Make newChild occupy the location that oldChild used to have. Note that newChild will first be
   * removed from its previous parent, if any. Equivalent to inserting newChild before oldChild,
   * then removing oldChild.
   *
   * @return oldChild, in its new state (removed).
   * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a type that shouldn't be a child
   *     of this node, or if newChild is one of our ancestors.
   * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a different owner document than we do.
   * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of this node.
   * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is read-only.
   */
  public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
    // If Mutation Events are being generated, this operation might
    // throw aggregate events twice when modifying an Attr -- once
    // on insertion and once on removal. DOM Level 2 does not specify
    // this as either desirable or undesirable, but hints that
    // aggregations should be issued only once per user request.

    // notify document
    ownerDocument.replacingNode(this);

    internalInsertBefore(newChild, oldChild, true);
    if (newChild != oldChild) {
      internalRemoveChild(oldChild, true);
    }

    // notify document
    ownerDocument.replacedNode(this);

    return oldChild;
  }