///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2003 Intel Corporation 
// All rights reserved. 
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met: 
//
// * Redistributions of source code must retain the above copyright notice, 
// this list of conditions and the following disclaimer. 
// * Redistributions in binary form must reproduce the above copyright notice, 
// this list of conditions and the following disclaimer in the documentation 
// and/or other materials provided with the distribution. 
// * Neither name of Intel Corporation nor the names of its contributors 
// may be used to endorse or promote products derived from this software 
// without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

#include "ixmlparser.h"

/*================================================================
*   ixmlElement_Init
*       Initializes an element node.
*       External function.
*
*=================================================================*/
void
ixmlElement_init( IN IXML_Element * element )
{
    if( element != NULL ) {
        memset( element, 0, sizeof( IXML_Element ) );
    }
}

/*================================================================
*   ixmlElement_getTagName
*       Gets the element node's tagName
*       External function.
*
*=================================================================*/
const DOMString
ixmlElement_getTagName( IN IXML_Element * element )
{

    if( element != NULL ) {
        return element->tagName;
    } else {
        return NULL;
    }
}

/*================================================================
*   ixmlElement_setTagName
*       Sets the given element's tagName.
*   Parameters:
*       tagName: new tagName for the element.
*
*=================================================================*/
int
ixmlElement_setTagName( IN IXML_Element * element,
                        IN const char *tagName )
{
    int rc = IXML_SUCCESS;

    assert( ( element != NULL ) && ( tagName != NULL ) );
    if( ( element == NULL ) || ( tagName == NULL ) ) {
        return IXML_FAILED;
    }

    if( element->tagName != NULL ) {
        free( element->tagName );
    }

    element->tagName = strdup( tagName );
    if( element->tagName == NULL ) {
        rc = IXML_INSUFFICIENT_MEMORY;
    }

    return rc;

}

/*================================================================
*   ixmlElement_getAttribute
*       Retrievea an attribute value by name.
*       External function.
*   Parameters:
*       name: the name of the attribute to retrieve.
*   Return Values:
*       attribute value as a string, or the empty string if that attribute
*       does not have a specified value.
*
*=================================================================*/
const DOMString
ixmlElement_getAttribute( IN IXML_Element * element,
                          IN const DOMString name )
{
    IXML_Node *attrNode;

    if( ( element == NULL ) || ( name == NULL ) ) {
        return NULL;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, name ) == 0 ) { // found it
            return attrNode->nodeValue;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return NULL;
}

/*================================================================
*   ixmlElement_setAttribute
*       Adds a new attribute.  If an attribute with that name is already
*       present in the element, its value is changed to be that of the value
*       parameter. If not, a new attribute is inserted into the element.
*
*       External function.
*   Parameters:
*       name: the name of the attribute to create or alter.
*       value: value to set in string form
*   Return Values:
*       IXML_SUCCESS or failure code.    
*
*=================================================================*/
int
ixmlElement_setAttribute( IN IXML_Element * element,
                          IN const char *name,
                          IN const char *value )
{
    IXML_Node *attrNode;
    IXML_Attr *newAttrNode;
    short errCode = IXML_SUCCESS;

    if( ( element == NULL ) || ( name == NULL ) || ( value == NULL ) ) {
        errCode = IXML_INVALID_PARAMETER;
        goto ErrorHandler;
    }

    if( Parser_isValidXmlName( name ) == FALSE ) {
        errCode = IXML_INVALID_CHARACTER_ERR;
        goto ErrorHandler;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, name ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode == NULL ) {    // add a new attribute
        errCode =
            ixmlDocument_createAttributeEx( ( IXML_Document * ) element->n.
                                            ownerDocument, name,
                                            &newAttrNode );
        if( errCode != IXML_SUCCESS ) {
            goto ErrorHandler;
        }

        attrNode = ( IXML_Node * ) newAttrNode;

        attrNode->nodeValue = strdup( value );
        if( attrNode->nodeValue == NULL ) {
            ixmlAttr_free( newAttrNode );
            errCode = IXML_INSUFFICIENT_MEMORY;
            goto ErrorHandler;
        }

        errCode =
            ixmlElement_setAttributeNode( element, newAttrNode, NULL );
        if( errCode != IXML_SUCCESS ) {
            ixmlAttr_free( newAttrNode );
            goto ErrorHandler;
        }

    } else {
        if( attrNode->nodeValue != NULL ) { // attribute name has a value already
            free( attrNode->nodeValue );
        }

        attrNode->nodeValue = strdup( value );
        if( attrNode->nodeValue == NULL ) {
            errCode = IXML_INSUFFICIENT_MEMORY;
        }
    }

  ErrorHandler:
    return errCode;
}

/*================================================================
*   ixmlElement_removeAttribute
*       Removes an attribute value by name. The attribute node is
*       not removed.
*       External function.
*   Parameters:
*       name: the name of the attribute to remove.
*   Return Values:
*       IXML_SUCCESS or error code.
*
*=================================================================*/
int
ixmlElement_removeAttribute( IN IXML_Element * element,
                             IN const char *name )
{

    IXML_Node *attrNode;

    if( ( element == NULL ) || ( name == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, name ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode != NULL ) {    // has the attribute
        if( attrNode->nodeValue != NULL ) {
            free( attrNode->nodeValue );
            attrNode->nodeValue = NULL;
        }
    }

    return IXML_SUCCESS;
}

/*================================================================
*   ixmlElement_getAttributeNode
*       Retrieve an attribute node by name.
*       External function.        
*   Parameters:
*       name: the name(nodeName) of the attribute to retrieve.
*   Return Value:
*       The attr node with the specified name (nodeName) or NULL if
*       there is no such attribute.  
*
*=================================================================*/
IXML_Attr *
ixmlElement_getAttributeNode( IN IXML_Element * element,
                              IN const char *name )
{

    IXML_Node *attrNode;

    if( ( element == NULL ) || ( name == NULL ) ) {
        return NULL;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, name ) == 0 ) { // found it
            break;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return ( IXML_Attr * ) attrNode;

}

/*================================================================
*   ixmlElement_setAttributeNode
*       Adds a new attribute node.  If an attribute with that name(nodeName)
*       is already present in the element, it is replaced by the new one.
*       External function.
*   Parameters:
*       The attr node to add to the attribute list.
*   Return Value:
*       if newAttr replaces an existing attribute, the replaced
*       attr node is returned, otherwise NULL is returned.           
*
*=================================================================*/
int
ixmlElement_setAttributeNode( IN IXML_Element * element,
                              IN IXML_Attr * newAttr,
                              OUT IXML_Attr ** rtAttr )
{

    IXML_Node *attrNode;
    IXML_Node *node;
    IXML_Node *nextAttr = NULL;
    IXML_Node *prevAttr = NULL;
    IXML_Node *preSib,
     *nextSib;

    if( ( element == NULL ) || ( newAttr == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    if( newAttr->n.ownerDocument != element->n.ownerDocument ) {
        return IXML_WRONG_DOCUMENT_ERR;
    }

    if( newAttr->ownerElement != NULL ) {
        return IXML_INUSE_ATTRIBUTE_ERR;
    }

    newAttr->ownerElement = element;
    node = ( IXML_Node * ) newAttr;

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, node->nodeName ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode != NULL )      // already present, will replace by newAttr
    {
        preSib = attrNode->prevSibling;
        nextSib = attrNode->nextSibling;

        if( preSib != NULL ) {
            preSib->nextSibling = node;
        }

        if( nextSib != NULL ) {
            nextSib->prevSibling = node;
        }

        if( element->n.firstAttr == attrNode ) {
            element->n.firstAttr = node;
        }

        if( rtAttr != NULL ) {
            *rtAttr = ( IXML_Attr * ) attrNode;
        }
    } else                      // add this attribute 
    {
        if( element->n.firstAttr != NULL ) {
            prevAttr = element->n.firstAttr;
            nextAttr = prevAttr->nextSibling;
            while( nextAttr != NULL ) {
                prevAttr = nextAttr;
                nextAttr = prevAttr->nextSibling;
            }
            prevAttr->nextSibling = node;
            node->prevSibling = prevAttr;
        } else                  // this is the first attribute node
        {
            element->n.firstAttr = node;
            node->prevSibling = NULL;
            node->nextSibling = NULL;
        }

        if( rtAttr != NULL ) {
            *rtAttr = NULL;
        }
    }

    return IXML_SUCCESS;
}

/*================================================================
*   ixmlElement_findAttributeNode
*       Find a attribute node whose contents are the same as the oldAttr.
*       Internal only to parser.
*   Parameter:
*       oldAttr: the attribute node to match
*   Return:
*       if found it, the attribute node is returned,
*       otherwise, return NULL.
*
*=================================================================*/
IXML_Node *
ixmlElement_findAttributeNode( IN IXML_Element * element,
                               IN IXML_Attr * oldAttr )
{
    IXML_Node *attrNode;
    IXML_Node *oldAttrNode = ( IXML_Node * ) oldAttr;

    assert( ( element != NULL ) && ( oldAttr != NULL ) );

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) { // parentNode, prevSib, nextSib and ownerDocument doesn't matter
        if( ixmlNode_compare( attrNode, oldAttrNode ) == TRUE ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return attrNode;

}

/*================================================================
*   ixmlElement_removeAttributeNode	
*       Removes the specified attribute node.
*       External function.
*
*   Parameters:
*       oldAttr: the attr node to remove from the attribute list.
*       
*   Return Value:
*       IXML_SUCCESS or failure
*
*=================================================================*/
int
ixmlElement_removeAttributeNode( IN IXML_Element * element,
                                 IN IXML_Attr * oldAttr,
                                 OUT IXML_Attr ** rtAttr )
{
    IXML_Node *attrNode;
    IXML_Node *preSib,
     *nextSib;

    if( ( element == NULL ) || ( oldAttr == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    attrNode = ixmlElement_findAttributeNode( element, oldAttr );
    if( attrNode != NULL ) {    // has the attribute
        preSib = attrNode->prevSibling;
        nextSib = attrNode->nextSibling;

        if( preSib != NULL ) {
            preSib->nextSibling = nextSib;
        }

        if( nextSib != NULL ) {
            nextSib->prevSibling = preSib;
        }

        if( element->n.firstAttr == attrNode ) {
            element->n.firstAttr = nextSib;
        }

        /* ( IXML_Attr * ) */ attrNode->parentNode = NULL;
        /* ( IXML_Attr * ) */ attrNode->prevSibling = NULL;
        /* ( IXML_Attr * ) */ attrNode->nextSibling = NULL;
        *rtAttr = ( IXML_Attr * ) attrNode;
        return IXML_SUCCESS;

    } else {
        return IXML_NOT_FOUND_ERR;
    }

}

/*================================================================
*   ixmlElement_getElementsByTagName
*       Returns a nodeList of all descendant Elements with a given
*       tag name, in the order in which they are encountered in a preorder
*       traversal of this element tree.
*       External function.
*
*   Parameters:
*       tagName: the name of the tag to match on. The special value "*"
*       matches all tags.
*
*   Return Value:
*       a nodeList of matching element nodes.
*
*=================================================================*/
IXML_NodeList *
ixmlElement_getElementsByTagName( IN IXML_Element * element,
                                  IN const char *tagName )
{
    IXML_NodeList *returnNodeList = NULL;

    if( ( element != NULL ) && ( tagName != NULL ) ) {
        ixmlNode_getElementsByTagName( ( IXML_Node * ) element, tagName,
                                       &returnNodeList );
    }
    return returnNodeList;
}

/*================================================================
*   ixmlElement_getAttributeNS
*       Retrieves an attribute value by local name and namespace URI.
*       External function.
*
*   Parameters:
*       namespaceURI: the namespace URI of the attribute to retrieve.
*       localName: the local name of the attribute to retrieve.
*
*   Return Value:
*       the attr value as a string, or NULL if that attribute does
*       not have the specified value.
*
*=================================================================*/
const DOMString
ixmlElement_getAttributeNS( IN IXML_Element * element,
                            IN const DOMString namespaceURI,
                            IN const DOMString localName )
{
    IXML_Node *attrNode;

    if( ( element == NULL ) || ( namespaceURI == NULL )
        || ( localName == NULL ) ) {
        return NULL;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, localName ) == 0 && strcmp( attrNode->namespaceURI, namespaceURI ) == 0 ) {    // found it
            return attrNode->nodeValue;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return NULL;

}

/*================================================================
*   ixmlElement_setAttributeNS
*       Adds a new attribute. If an attribute with the same local name
*       and namespace URI is already present on the element, its prefix
*       is changed to be the prefix part of the qualifiedName, and its
*       value is changed to be the value parameter.  This value is a
*       simple string.
*       External function.
*
*   Parameter:
*       namespaceURI: the namespace of the attribute to create or alter.
*       qualifiedName: the qualified name of the attribute to create or alter.
*       value: the value to set in string form.
*
*   Return Value:
*       IXML_SUCCESS or failure 
*
*=================================================================*/
int
ixmlElement_setAttributeNS( IN IXML_Element * element,
                            IN const DOMString namespaceURI,
                            IN const DOMString qualifiedName,
                            IN const DOMString value )
{
    IXML_Node *attrNode = NULL;
    IXML_Node newAttrNode;
    IXML_Attr *newAttr;
    int rc;

    if( ( element == NULL ) || ( namespaceURI == NULL ) ||
        ( qualifiedName == NULL ) || ( value == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    if( Parser_isValidXmlName( qualifiedName ) == FALSE ) {
        return IXML_INVALID_CHARACTER_ERR;
    }

    ixmlNode_init( &newAttrNode );

    newAttrNode.nodeName = strdup( qualifiedName );
    if( newAttrNode.nodeName == NULL ) {
        return IXML_INSUFFICIENT_MEMORY;
    }

    rc = Parser_setNodePrefixAndLocalName( &newAttrNode );
    if( rc != IXML_SUCCESS ) {
        Parser_freeNodeContent( &newAttrNode );
        return rc;
    }
    // see DOM 2 spec page 59
    if( ( newAttrNode.prefix != NULL && namespaceURI == NULL ) ||
        ( strcmp( newAttrNode.prefix, "xml" ) == 0 &&
          strcmp( namespaceURI,
                  "http://www.w3.org/XML/1998/namespace" ) != 0 )
        || ( strcmp( qualifiedName, "xmlns" ) == 0
             && strcmp( namespaceURI,
                        "http://www.w3.org/2000/xmlns/" ) != 0 ) ) {
        Parser_freeNodeContent( &newAttrNode );
        return IXML_NAMESPACE_ERR;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, newAttrNode.localName ) == 0 &&
            strcmp( attrNode->namespaceURI, namespaceURI ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode != NULL ) {
        if( attrNode->prefix != NULL ) {
            free( attrNode->prefix );   // remove the old prefix
        }
        // replace it with the new prefix
        attrNode->prefix = strdup( newAttrNode.prefix );
        if( attrNode->prefix == NULL ) {
            Parser_freeNodeContent( &newAttrNode );
            return IXML_INSUFFICIENT_MEMORY;
        }

        if( attrNode->nodeValue != NULL ) {
            free( attrNode->nodeValue );
        }

        attrNode->nodeValue = strdup( value );
        if( attrNode->nodeValue == NULL ) {
            free( attrNode->prefix );
            Parser_freeNodeContent( &newAttrNode );
            return IXML_INSUFFICIENT_MEMORY;
        }

    } else {
        // add a new attribute
        rc = ixmlDocument_createAttributeNSEx( ( IXML_Document * )
                                               element->n.ownerDocument,
                                               namespaceURI, qualifiedName,
                                               &newAttr );
        if( rc != IXML_SUCCESS ) {
            return rc;
        }

        newAttr->n.nodeValue = strdup( value );
        if( newAttr->n.nodeValue == NULL ) {
            ixmlAttr_free( newAttr );
            return IXML_INSUFFICIENT_MEMORY;
        }

        if( ixmlElement_setAttributeNodeNS( element, newAttr, NULL ) !=
            IXML_SUCCESS ) {
            ixmlAttr_free( newAttr );
            return IXML_FAILED;
        }

    }

    Parser_freeNodeContent( &newAttrNode );
    return IXML_SUCCESS;
}

/*================================================================
*   ixmlElement_removeAttributeNS
*       Removes an attribute by local name and namespace URI. The replacing
*       attribute has the same namespace URI and local name, as well as
*       the original prefix.
*       External function.
*
*   Parameters:
*       namespaceURI: the namespace URI of the attribute to remove.
*       localName: the local name of the atribute to remove.
*
*   Return Value:
*       IXML_SUCCESS or failure.
*
*=================================================================*/
int
ixmlElement_removeAttributeNS( IN IXML_Element * element,
                               IN const DOMString namespaceURI,
                               IN const DOMString localName )
{
    IXML_Node *attrNode;

    if( ( element == NULL ) || ( namespaceURI == NULL )
        || ( localName == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, localName ) == 0 &&
            strcmp( attrNode->namespaceURI, namespaceURI ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode != NULL ) {    // has the attribute
        if( attrNode->nodeValue != NULL ) {
            free( attrNode->nodeValue );
            attrNode->nodeValue = NULL;
        }
    }

    return IXML_SUCCESS;

}

/*================================================================
*   ixmlElement_getAttributeNodeNS
*       Retrieves an attr node by local name and namespace URI. 
*       External function.
*
*   Parameter:
*       namespaceURI: the namespace of the attribute to retrieve.
*       localName: the local name of the attribute to retrieve.
*
*   Return Value:
*       The attr node with the specified attribute local name and 
*       namespace URI or null if there is no such attribute.
*
*=================================================================*/
IXML_Attr *
ixmlElement_getAttributeNodeNS( IN IXML_Element * element,
                                IN const DOMString namespaceURI,
                                IN const DOMString localName )
{

    IXML_Node *attrNode;

    if( ( element == NULL ) || ( namespaceURI == NULL )
        || ( localName == NULL ) ) {
        return NULL;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, localName ) == 0 && strcmp( attrNode->namespaceURI, namespaceURI ) == 0 ) {    // found it
            break;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return ( IXML_Attr * ) attrNode;

}

/*================================================================
*   ixmlElement_setAttributeNodeNS
*       Adds a new attribute. If an attribute with that local name and
*       that namespace URI is already present in the element, it is replaced
*       by the new one.
*       External function.
*
*   Parameter:
*       newAttr: the attr node to add to the attribute list.
*
*   Return Value:
*       If the newAttr attribute replaces an existing attribute with the
*       same local name and namespace, the replaced attr node is returned,
*       otherwise null is returned.
*
*=================================================================*/
int
ixmlElement_setAttributeNodeNS( IN IXML_Element * element,
                                IN IXML_Attr * newAttr,
                                OUT IXML_Attr ** rtAttr )
{
    IXML_Node *attrNode;
    IXML_Node *node;
    IXML_Node *prevAttr = NULL,
     *nextAttr = NULL;
    IXML_Node *preSib,
     *nextSib;

    if( ( element == NULL ) || ( newAttr == NULL ) ) {
        return IXML_INVALID_PARAMETER;
    }

    if( newAttr->n.ownerDocument != element->n.ownerDocument ) {
        return IXML_WRONG_DOCUMENT_ERR;
    }

    if( ( newAttr->ownerElement != NULL )
        && ( newAttr->ownerElement != element ) ) {
        return IXML_INUSE_ATTRIBUTE_ERR;
    }

    newAttr->ownerElement = element;
    node = ( IXML_Node * ) newAttr;

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, node->localName ) == 0 &&
            strcmp( attrNode->namespaceURI, node->namespaceURI ) == 0 ) {
            break;              //found it
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    if( attrNode != NULL )      // already present, will replace by newAttr
    {
        preSib = attrNode->prevSibling;
        nextSib = attrNode->nextSibling;

        if( preSib != NULL ) {
            preSib->nextSibling = node;
        }

        if( nextSib != NULL ) {
            nextSib->prevSibling = node;
        }

        if( element->n.firstAttr == attrNode ) {
            element->n.firstAttr = node;
        }

        *rtAttr = ( IXML_Attr * ) attrNode;

    } else                      // add this attribute 
    {
        if( element->n.firstAttr != NULL )  // element has attribute already
        {
            prevAttr = element->n.firstAttr;
            nextAttr = prevAttr->nextSibling;
            while( nextAttr != NULL ) {
                prevAttr = nextAttr;
                nextAttr = prevAttr->nextSibling;
            }
            prevAttr->nextSibling = node;
        } else                  // this is the first attribute node
        {
            element->n.firstAttr = node;
            node->prevSibling = NULL;
            node->nextSibling = NULL;
        }

        if( rtAttr != NULL ) {
            *rtAttr = NULL;
        }
    }

    return IXML_SUCCESS;
}

/*================================================================
*   ixmlElement_getElementsByTagNameNS
*       Returns a nodeList of all the descendant Elements with a given
*       local name and namespace in the order in which they are encountered
*       in a preorder traversal of the element tree.
*       External function.
*
*   Parameters:
*       namespaceURI: the namespace URI of the elements to match on. The
*               special value "*" matches all namespaces.
*       localName: the local name of the elements to match on. The special
*               value "*" matches all local names.
*
*   Return Value:
*       A new nodeList object containing all the matched Elements.
*
*=================================================================*/
IXML_NodeList *
ixmlElement_getElementsByTagNameNS( IN IXML_Element * element,
                                    IN const DOMString namespaceURI,
                                    IN const DOMString localName )
{
    IXML_Node *node = ( IXML_Node * ) element;
    IXML_NodeList *nodeList = NULL;

    if( ( element != NULL ) && ( namespaceURI != NULL )
        && ( localName != NULL ) ) {
        ixmlNode_getElementsByTagNameNS( node, namespaceURI, localName,
                                         &nodeList );
    }

    return nodeList;
}

/*================================================================
*   ixmlElement_hasAttribute
*       Returns true when an attribute with a given name is specified on
*       this element, false otherwise.
*       External function.
*
*   Parameters:
*       name: the name of the attribute to look for.
*
*   Return Value:
*       ture if an attribute with the given name is specified on this
*       element, false otherwise.
*
*=================================================================*/
BOOL
ixmlElement_hasAttribute( IN IXML_Element * element,
                          IN const DOMString name )
{

    IXML_Node *attrNode;

    if( ( element == NULL ) || ( name == NULL ) ) {
        return FALSE;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->nodeName, name ) == 0 ) {
            return TRUE;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return FALSE;
}

/*================================================================
*   ixmlElement_hasAttributeNS
*       Returns true when attribute with a given local name and namespace
*       URI is specified on this element, false otherwise.
*       External function.
*
*   Parameters:
*       namespaceURI: the namespace URI of the attribute to look for.
*       localName: the local name of the attribute to look for.
*
*   Return Value:
*       true if an attribute with the given local name and namespace URI
*       is specified, false otherwise.
*
*=================================================================*/
BOOL
ixmlElement_hasAttributeNS( IN IXML_Element * element,
                            IN const DOMString namespaceURI,
                            IN const DOMString localName )
{

    IXML_Node *attrNode;

    if( ( element == NULL ) || ( namespaceURI == NULL )
        || ( localName == NULL ) ) {
        return FALSE;
    }

    attrNode = element->n.firstAttr;
    while( attrNode != NULL ) {
        if( strcmp( attrNode->localName, localName ) == 0 &&
            strcmp( attrNode->namespaceURI, namespaceURI ) == 0 ) {
            return TRUE;
        } else {
            attrNode = attrNode->nextSibling;
        }
    }

    return FALSE;
}

/*================================================================
*   ixmlElement_free
*       frees a element node.
*       External function.
*
*=================================================================*/
void
ixmlElement_free( IN IXML_Element * element )
{
    if( element != NULL ) {
        ixmlNode_free( ( IXML_Node * ) element );
    }
}
