TOHW_m_dom_publics(`

  public :: getNamedItem
  public :: getNamedItem_Value
  public :: getNamedItem_Value_length
  public :: setNamedItem
  public :: removeNamedItem
!  public :: item
!  public :: getLength
  public :: getNamedItemNS
  public :: getNamedItemNS_Value
  public :: getNamedItemNS_Value_length
  public :: setNamedItemNS
  public :: removeNamedItemNS

!  public :: append
  public :: setReadOnlyMap
  public :: destroyNamedNodeMap


  interface item
    module procedure item_nnm
  end interface

  interface getLength
    module procedure getLength_nnm
  end interface

')`'dnl
dnl
TOHW_m_dom_contents(`

  TOHW_function(getNamedItem, (map, name), np)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: name
    type(Node), pointer :: np

    integer :: i

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    do i = 1, map%length
      if (str_vs(map%nodes(i)%this%nodeName)==name) then
        np => map%nodes(i)%this
        return
      endif
    enddo

    np => null()

  end function getNamedItem


  pure function getNamedItem_Value_length(map, name) result(n)
    type(NamedNodeMap), intent(in) :: map
    character(len=*), intent(in) :: name
    integer :: n

    integer :: i

    do i = 1, map%length
      if (str_vs(map%nodes(i)%this%nodeName)==name) then
        n = getNodeValue_len(map%nodes(i)%this, .true.)
        exit
      endif
    enddo
    n = 0

  end function getNamedItem_Value_length


  TOHW_function(getNamedItem_Value, (map, name), c)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: name
    character(len=getNamedItem_Value_length(map, name)) :: c

    integer :: i

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    c = ""
    do i = 1, map%length
      if (str_vs(map%nodes(i)%this%nodeName)==name) then
        c = getNodeValue(map%nodes(i)%this)
        return
      endif
    enddo

  end function getNamedItem_Value


  TOHW_function(setNamedItem, (map, arg), np)
    type(NamedNodeMap), pointer :: map
    type(Node), pointer :: arg
    type(Node), pointer :: np

    integer :: i

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    if (.not.associated(arg)) then
      TOHW_m_dom_throw_error(FoX_NODE_IS_NULL)
    endif

    if (map%readonly) then
      TOHW_m_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR)
    elseif (map%ownerElement%nodeType==ELEMENT_NODE) then
      if (.not.associated(map%ownerElement%ownerDocument, arg%ownerDocument)) then
        TOHW_m_dom_throw_error(WRONG_DOCUMENT_ERR)
      elseif (getNodeType(arg)/=ATTRIBUTE_NODE) then
        !Additional check from DOM 3
        TOHW_m_dom_throw_error(HIERARCHY_REQUEST_ERR)
      endif
    endif

    if (getNodeType(arg)==ATTRIBUTE_NODE) then
      call setSpecified(arg, .true.) ! just in case it isnt already
      if (associated(map%ownerElement, getOwnerElement(arg))) then
        ! we are looking at literally the same node
        np => arg
        return
      elseif (associated(getOwnerElement(arg))) then
        TOHW_m_dom_throw_error(INUSE_ATTRIBUTE_ERR)    
      endif
      arg%elExtras%ownerElement => map%ownerElement
    endif

    do i = 0, getLength(map)-1
      np => item(map, i)
      if (getNodeName(np)==getNodeName(arg)) then
        map%nodes(i+1)%this => arg
        exit
      endif
    enddo

    if (i<getLength(map)) then
      if (getGCstate(getOwnerDocument(map%ownerElement)).and.np%inDocument) then
        call removeNodesFromDocument(getOwnerDocument(map%ownerElement), np)
        np%inDocument = .false.
      endif
    else
      !   If not found, insert it at the end of the linked list
      np => null()
      call append_nnm(map, arg)
    endif

    if (map%ownerElement%nodeType==ELEMENT_NODE) then
      if (getGCstate(getOwnerDocument(map%ownerElement))) then
        ! We need to worry about importing this node
        if (map%ownerElement%inDocument) then
          if (.not.arg%inDocument) &
            call putNodesInDocument(getOwnerDocument(map%ownerElement), arg)
        else
          if (arg%inDocument) &
            call removeNodesFromDocument(getOwnerDocument(map%ownerElement), arg)
          endif
      endif
    endif
    ! Otherwise we only ever setNNM when building the doc, so we know this
    ! does not matter

  end function setNamedItem


  TOHW_function(removeNamedItem, (map, name), np)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: name
    type(Node), pointer :: np

    type(xml_doc_state), pointer :: xds
    type(element_t), pointer :: elem
    type(ListNode), pointer :: temp_nl(:)
    integer :: i, i2, i_default

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    if (map%readonly) then
      TOHW_m_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR)
    endif

    do i = 0, map%length-1
      np => item(map, i)
      if (getNodeName(np)==name) then
        xds => getXds(getOwnerDocument(map%ownerElement))
        elem => get_element(xds%element_list, getNodeName(map%ownerElement))
        if (associated(elem)) then
          i_default = default_att_index(elem, name)
          if (i_default>0) then ! there is a default value
            ! Well swap the old one out & put a new one in.
            ! Do *nothing* about namespace handling at this stage,
            ! wait until we are asked for namespace normalization
            if (getParameter( &
              getDomConfig(getOwnerDocument(map%ownerElement)), &
                           "namespaces")) then
              np => createAttributeNS(getOwnerDocument(map%ownerElement), "", name)
            else
              np => createAttribute(getOwnerDocument(map%ownerElement), name)
            endif
            call setValue(np, str_vs(elem%attlist%list(i_default)%default))
            call setSpecified(np, .false.)
            np => setNamedItem(map, np)
            call setSpecified(np, .true.)
            return
          endif
        endif
        ! Otherwise there was no default value, so we just remove the node.
        ! Grab this node
        if (getNodeType(np)==ATTRIBUTE_NODE) np%elExtras%ownerElement => null()
        ! and shrink the node list
        temp_nl => map%nodes
        allocate(map%nodes(size(temp_nl)-1))
        do i2 = 1, i
          map%nodes(i2)%this => temp_nl(i2)%this
        enddo
        do i2 = i + 2, map%length
          map%nodes(i2-1)%this => temp_nl(i2)%this
        enddo
        map%length = size(map%nodes)
        deallocate(temp_nl)
        if (np%inDocument.and.getGCstate(getOwnerDocument(map%ownerElement))) &
          call removeNodesFromDocument(getOwnerDocument(map%ownerElement), np)
        !otherwise we are only going to destroy these nodes anyway,
        ! and finish
        return
      endif
    enddo

    TOHW_m_dom_throw_error(NOT_FOUND_ERR)

  end function removeNamedItem


  TOHW_function(item_nnm, (map, index), np)
    type(NamedNodeMap), pointer :: map
    integer, intent(in) :: index
    type(Node), pointer :: np
    
    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    if (index<0 .or. index>map%length-1) then
      np => null()
    else
      np => map%nodes(index+1)%this
    endif

   end function item_nnm

  TOHW_function(getLength_nnm, (map), n)
    type(namedNodeMap), pointer :: map
    integer :: n

    if (.not.associated(map)) then
       TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    n = map%length
    
  end function getLength_nnm


  TOHW_function(getNamedItemNS, (map, namespaceURI, localName), np)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: namespaceURI
    character(len=*), intent(in) :: localName
    type(Node), pointer :: np

    integer :: i

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    elseif (map%ownerElement%nodeType/=ELEMENT_NODE) then
      np => null()
      return
    endif

    do i = 0, getLength(map) - 1
      np => item(map, i)
      if (getNamespaceURI(np)==namespaceURI &
        .and. getLocalName(np)==localName) then
        return
      endif
    enddo
    np => null()

  end function getNamedItemNS


  pure function getNamedItemNS_Value_length(map, p, namespaceURI, localName) result(n)
    type(NamedNodeMap), intent(in) :: map
    logical, intent(in) :: p
    character(len=*), intent(in) :: namespaceURI
    character(len=*), intent(in) :: localName
    integer :: n

    integer :: i

    n = 0
    if (.not.p) return
    if (map%ownerElement%nodeType/=ELEMENT_NODE) return

    do i = 1, map%length
      if (str_vs(map%nodes(i)%this%elExtras%namespaceURI)==namespaceURI &
        .and. str_vs(map%nodes(i)%this%elExtras%localName)==localName) then
        n = getNodeValue_len(map%nodes(i)%this, .true.)
        exit
      endif
    enddo

  end function getNamedItemNS_Value_length


  TOHW_function(getNamedItemNS_Value, (map, namespaceURI, localName), c)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: namespaceURI
    character(len=*), intent(in) :: localName
#ifdef RESTRICTED_ASSOCIATED_BUG
    character(len=getNamedItemNS_Value_length(map, .true., namespaceURI, localName)) :: c
#else
    character(len=getNamedItemNS_Value_length(map, associated(map), namespaceURI, localName)) :: c
#endif

    integer :: i
    type(Node), pointer :: np

    if (.not.associated(map)) then
       TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    c = ""
    if (map%ownerElement%nodeType/=ELEMENT_NODE) return
    do i = 0, getLength(map) - 1
      np => item(map, i)
      if (getNamespaceURI(np)==namespaceURI &
        .and. getLocalName(np)==localName) then
        c = getNodeValue(np)
        return
      endif
    enddo

  end function getNamedItemNS_Value


  TOHW_function(setNamedItemNS, (map, arg), np)
    type(NamedNodeMap), pointer :: map
    type(Node), pointer :: arg
    type(Node), pointer :: np

    integer :: i
    character, pointer, dimension(:) :: arg_ns, arg_ln, map_ns, map_ln

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    if (.not.associated(arg)) then
      TOHW_m_dom_throw_error(FoX_NODE_IS_NULL)
    endif

    if (map%readonly) then
      TOHW_m_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR)
    elseif (map%ownerElement%nodeType==ELEMENT_NODE) then
      if (.not.associated(map%ownerElement%ownerDocument, arg%ownerDocument)) then
        TOHW_m_dom_throw_error(WRONG_DOCUMENT_ERR)
      elseif (getNodeType(arg)/=ATTRIBUTE_NODE) then
        !Additional check from DOM 3
        TOHW_m_dom_throw_error(HIERARCHY_REQUEST_ERR)
      endif
    endif

    if (getNodeType(arg)==ATTRIBUTE_NODE) then
      call setSpecified(arg, .true.) ! in case it isnt already
      if (associated(map%ownerElement, getOwnerElement(arg))) then
        ! we are looking at literally the same node, so do nothing else
        np => arg
        return
      elseif (associated(getOwnerElement(arg))) then
        TOHW_m_dom_throw_error(INUSE_ATTRIBUTE_ERR)    
      endif
      arg%elExtras%ownerElement => map%ownerElement
    endif

    do i = 0, getLength(map) - 1
      np => item(map, i)
      if (getLocalName(arg)==getLocalName(np).and.getNamespaceURI(arg)==getNamespaceURI(np)) then
        map%nodes(i+1)%this => arg
        exit
      endif
    enddo

    if (i<getLength(map)) then
      if (getGCstate(getOwnerDocument(map%ownerElement)).and.np%inDocument) then
        call removeNodesFromDocument(getOwnerDocument(map%ownerElement), np)
        arg%inDocument = .false.
      endif
    else
      !   If not found, insert it at the end of the linked list
      np => null()
      call append_nnm(map, arg)
    endif

    if (map%ownerElement%nodeType==ELEMENT_NODE) then
      if (getGCstate(getOwnerDocument(map%ownerElement))) then
        ! We need to worry about importing this node
        if (map%ownerElement%inDocument) then
          if (.not.arg%inDocument) &
            call putNodesInDocument(getOwnerDocument(map%ownerElement), arg)
        else
          if (arg%inDocument) &
            call removeNodesFromDocument(getOwnerDocument(map%ownerElement), arg)
        endif
      endif
    endif

  end function setNamedItemNS


  TOHW_function(removeNamedItemNS, (map, namespaceURI, localName), np)
    type(NamedNodeMap), pointer :: map
    character(len=*), intent(in) :: namespaceURI
    character(len=*), intent(in) :: localName
    type(Node), pointer :: np

    type(xml_doc_state), pointer :: xds
    type(element_t), pointer :: elem
    type(ListNode), pointer :: temp_nl(:)
    integer :: i, i2, i_default

    if (.not.associated(map)) then
      TOHW_m_dom_throw_error(FoX_MAP_IS_NULL)
    endif

    if (map%readonly) then
      TOHW_m_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR)
    endif

    do i = 0, getLength(map) - 1
      np => item(map, i)
      if (getNamespaceURI(np)==namespaceURI &
          .and. getLocalName(np)==localName) then
        ! Grab this node
        xds => getXds(getOwnerDocument(map%ownerElement))
        elem => get_element(xds%element_list, getNodeName(map%ownerElement))
        if (associated(elem)) then
          i_default = default_att_index(elem, getName(np))
          if (i_default>0) then ! there is a default value
            ! Well swap the old one out & put a new one in.
            ! Do *nothing* about namespace handling at this stage,
            ! wait until we are asked for namespace normalization
            np => createAttribute(getOwnerDocument(map%ownerElement), getName(np))
            call setValue(np, str_vs(elem%attlist%list(i_default)%default))
            call setSpecified(np, .false.)
            np => setNamedItem(map, np)
            call setSpecified(np, .true.)
            return
          endif
        endif
        ! Otherwise there was no default value, so we just remove the node.
        ! and shrink the node list
        if (getNodeType(np)==ATTRIBUTE_NODE) np%elExtras%ownerElement => null()
        temp_nl => map%nodes
        allocate(map%nodes(size(temp_nl)-1))
        do i2 = 1, i
          map%nodes(i2)%this => temp_nl(i2)%this
        enddo
        do i2 = i + 2, map%length
          map%nodes(i2-1)%this => temp_nl(i2)%this
        enddo
        map%length = size(map%nodes)
        deallocate(temp_nl)
        if (np%inDocument.and.getGCstate(getOwnerDocument(map%ownerElement))) &
          call removeNodesFromDocument(getOwnerDocument(map%ownerElement), np)
        !otherwise we are only going to destroy these nodes anyway,
        ! and finish
        return
      endif
    enddo

    TOHW_m_dom_throw_error(NOT_FOUND_ERR)

  end function removeNamedItemNS


  subroutine append_nnm(map, arg)
    type(namedNodeMap), pointer :: map
    type(node), pointer :: arg

    type(ListNode), pointer :: temp_nl(:)
    integer :: i

    if (.not.associated(map%nodes)) then
      allocate(map%nodes(1))
      map%nodes(1)%this => arg
      map%length = 1
    else
      temp_nl => map%nodes
      allocate(map%nodes(size(temp_nl)+1))
      do i = 1, size(temp_nl)
        map%nodes(i)%this => temp_nl(i)%this
      enddo
      deallocate(temp_nl)
      map%nodes(size(map%nodes))%this => arg
      map%length = size(map%nodes)
    endif
    if (getNodeType(arg)==ATTRIBUTE_NODE) arg%elExtras%ownerElement => map%ownerElement

   end subroutine append_nnm


  subroutine setReadOnlyMap(map, r)
    type(namedNodeMap), pointer :: map
    logical, intent(in) :: r

    map%readonly = r
  end subroutine setReadOnlyMap

  subroutine destroyNamedNodeMap(map)
    type(namedNodeMap), pointer :: map

    if (associated(map%nodes)) deallocate(map%nodes)
    deallocate(map)
 end subroutine destroyNamedNodeMap

')`'dnl
