2005/5/9

     
 

LibXMLElement.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright(C) 2000-2003 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_xml/src/acdk/xml/libxmldom/LibXMLElement.cpp,v 1.8 2005/02/20 13:56:30 kommer Exp $

#include "LibXMLElement.h"
#include "LibXMLPathNodeList.h"

#include "LibXMLDOMInternals.h"



namespace acdk {
namespace xml {
namespace libxmldom {




using namespace org::w3c::dom;

RString 
LibXMLElement::getAttribute(IN(RString) name)
{
  xmlChar* value = xmlGetProp(_nodePtr, STR2XML(name));
  if (value == 0)
    return "";
  return XML2STR(value);
}

void 
LibXMLElement::setAttribute(IN(RString) name, IN(RString) value) THROWS1(org::w3c::dom::RDOMException)
{
  if (xmlValidateName(STR2XML(name), 0) != 0)
    THROW2(DOMException, INVALID_CHARACTER_ERR, "Name of attribute is invalid");
  xmlSetProp(_nodePtr, STR2XML(name), STR2XML(value));
}
  
org::w3c::dom::RAttr 
LibXMLElement::getAttributeNode(IN(RString) name)
{
  xmlAttrPtr attr = xmlHasProp(_nodePtr, STR2XML(name));
  if (attr == 0)
    return Nil;
  return (org::w3c::dom::RAttr)LibXMLNode::newInstance((xmlNodePtr) attr);
}
  
xmlNodePtr _getNodePtr(IN(org::w3c::dom::RNode) node)
{
  if (instanceof(node, LibXMLNode) == false)
    THROW2(DOMException, NOT_FOUND_ERR, "Node is not a LibXMLNode");
  return RLibXMLNode(node)->getNodePtr();
}

void
_addAttribute(xmlNodePtr node, xmlAttrPtr attr)
{
  xmlAttrPtr cur = node->properties;
  if (cur == 0)
  {
    node->properties = attr;
    attr->prev = 0;
    attr->next = 0;
    attr->parent = node;
    attr->doc = node->doc;
  }
  else
  {
    while (cur->next != 0)
      cur = cur->next;
    cur->next = attr;
    attr->prev = cur;
    attr->next = NULL;
    attr->parent = node;
    attr->doc = node->doc;
  }
}

org::w3c::dom::RAttr 
LibXMLElement::setAttributeNode(IN(org::w3c::dom::RAttr) newAttr) THROWS1(org::w3c::dom::RDOMException)
{
  
  xmlAttrPtr new_attr = (xmlAttrPtr)_getNodePtr(&newAttr);
  if (new_attr->parent != 0)
    THROW2(DOMException, INUSE_ATTRIBUTE_ERR, "");
  if (new_attr->doc != _nodePtr->doc)
    THROW2(DOMException, WRONG_DOCUMENT_ERR, "");
  xmlAttrPtr old_attr = xmlHasProp(_nodePtr, new_attr->name);
  if (old_attr != 0)
      xmlUnlinkNode((xmlNodePtr)old_attr);
  _addAttribute(_nodePtr, new_attr);
  return (org::w3c::dom::RAttr)LibXMLNode::newInstance((xmlNodePtr) new_attr);
}

org::w3c::dom::RAttr 
LibXMLElement::removeAttributeNode(IN(org::w3c::dom::RAttr) oldAttr) THROWS1(org::w3c::dom::RDOMException)
{
  xmlAttrPtr attr = (xmlAttrPtr)_getNodePtr(&oldAttr);
  xmlUnlinkNode((xmlNodePtr)attr);
  return oldAttr;
}

xmlXPathContextPtr
_createContextPathPtr(xmlNodePtr node)
{
  xmlXPathContextPtr ctx = xmlXPathNewContext(node->doc);
  ctx->node = node;
  return ctx;
}

org::w3c::dom::RNodeList 
_getElementsByTagName(xmlNodePtr _nodePtr, IN(RString) name)
{
  RString format;
  if (name->equals("*") == true)
    format = "descendant-or-self::*[node-type()=1]";
  else
    format = SBSTR("descendant-or-self::*[name()='" << name << "']");

  RString rformat = STR2XMLSTR(format);
  
  xmlXPathContextPtr ctx = _createContextPathPtr(_nodePtr);
  xmlXPathObjectPtr eval = 0;
  if (ctx != 0)
  {
    eval = xmlXPathEval((const xmlChar*)rformat->c_str(), ctx);
    xmlXPathFreeContext(ctx);
  }
  return new LibXMLPathNodeList(eval);
}

org::w3c::dom::RNodeList 
LibXMLElement::getElementsByTagName(IN(RString) name)
{
  return _getElementsByTagName(_nodePtr, name);
}
  
RString 
LibXMLElement::getAttributeNS(IN(RString) namespaceURI, IN(RString) localName)
{
  RString value = Nil;
  if (namespaceURI == Nil)
    value = XML2STR(xmlGetNoNsProp(_nodePtr, STR2XML(localName)));
  else
    value = XML2STR(xmlGetNsProp(_nodePtr, STR2XML(localName), STR2XML(namespaceURI)));
  if (value == Nil)
    return "";
  return value;
}

const xmlChar*
_getLocalName(const xmlChar* fqName)
{
  xmlChar *prefix = 0;
  const xmlChar* localName = xmlSplitQName2(fqName, &prefix);
  if (localName == 0)
    return fqName;
  return localName;
}

const xmlChar*
_getPrefix(const xmlChar* fqName)
{
  xmlChar *prefix = 0;
  const xmlChar* localName = xmlSplitQName2(fqName, &prefix);
  if (localName == 0)
    return 0;
  return prefix;
}
  
void 
LibXMLElement::setAttributeNS(IN(RString) namespaceURI, IN(RString) qualifiedName, IN(RString) value) THROWS1(org::w3c::dom::RDOMException)
{
  if (xmlValidateQName (STR2XML(qualifiedName), 0) != 0)
    THROW2(DOMException, INVALID_CHARACTER_ERR, "");
  if (namespaceURI == Nil)
      xmlSetProp(_nodePtr, STR2XML(qualifiedName), STR2XML(value));
  else
  {
    RString uvalue = STR2XMLSTR(value);
    RString uqname = STR2XMLSTR(qualifiedName);
    const xmlChar* prefixc = _getPrefix((const xmlChar*)uvalue->c_str());
    const xmlChar* localNamec = _getLocalName((const xmlChar*)uqname->c_str());
    xmlNsPtr ns = xmlNewNs(_nodePtr, STR2XML(namespaceURI), prefixc);
    xmlSetNsProp(_nodePtr, ns, prefixc, (const xmlChar*)uvalue->c_str());
  }
}

bool
_match(const xmlChar* name, xmlNodePtr node)
{
  switch (node->type)
  {
  case XML_ELEMENT_NODE:
  case XML_ATTRIBUTE_NODE:
    return xmlStrcmp (node->name, name) == 0;
  default:
    return false;
  }
}

bool
_matchNS(const xmlChar* uri, const xmlChar* localName, xmlNodePtr node)
{
  switch (node->type)
  {
  case XML_ELEMENT_NODE:
  case XML_ATTRIBUTE_NODE:
  {
    int len = 0; 
    const xmlChar *nodeLocalName = 0;
    if (xmlSplitQName3(node->name, &len) != 0)
    {
      nodeLocalName = node->name + len;
    }
    else
    {
      nodeLocalName = node->name;
    }
    xmlNsPtr ns = node->ns;
    if (ns == 0 || ns->href == 0)
    {
      if (uri != 0)
      {
        return true;
      }
      return xmlStrcmp (localName, nodeLocalName) == 0;
    }
    if (uri == 0)
      return true;
    return xmlStrcmp(localName, nodeLocalName) == 0 && xmlStrcmp(uri, ns->href) == 0;
  }
  default:
    return false;
  }
}

org::w3c::dom::RAttr 
LibXMLElement::getAttributeNodeNS(IN(RString) namespaceURI, IN(RString) localName)
{
  xmlAttrPtr attr = _nodePtr->properties;
  while (attr != 0)
  {
    if (namespaceURI == Nil)
    {
      if (_match(STR2XML(localName), (xmlNodePtr)attr) == false)
        break;
    }
    else
    {
      if (_matchNS(STR2XML(namespaceURI), STR2XML(localName), (xmlNodePtr)attr) == false)
        break;
    }
    attr = attr->next;
  }
  return (org::w3c::dom::RAttr)newInstance((xmlNodePtr)attr);
}

org::w3c::dom::RAttr 
LibXMLElement::setAttributeNodeNS(IN(org::w3c::dom::RAttr) newAttr) THROWS1(org::w3c::dom::RDOMException)
{
  xmlAttrPtr new_attr = (xmlAttrPtr) _getNodePtr(&newAttr);
  if (new_attr->parent != 0)
    THROW2(DOMException, INUSE_ATTRIBUTE_ERR, ""); 
  if (new_attr->doc != _nodePtr->doc)
    THROW2(DOMException, WRONG_DOCUMENT_ERR, ""); 

  const xmlChar* uri = (new_attr->ns != 0) ? new_attr->ns->href : 0;
  xmlAttrPtr old_attr = xmlHasNsProp(_nodePtr, new_attr->name, uri);
  if (old_attr != 0)
      xmlUnlinkNode((xmlNodePtr)old_attr);

  _addAttribute(_nodePtr, new_attr);
  if (old_attr == 0)
    return Nil;
  return (org::w3c::dom::RAttr)newInstance((xmlNodePtr)old_attr, true); 
}

org::w3c::dom::RNodeList 
_getElementsByTagNameNS(xmlNodePtr _nodePtr, IN(RString) namespaceURI, IN(RString) localName)
{
  if (_nodePtr == 0)
    return Nil;

  RString format;
  if (namespaceURI == Nil)
  {
    RString format;
    if (localName->equals("*") == true)
      format = "descendant-or-self::*[namespace-uri()='' and node-type()=1]";
    else
      format = SBSTR("descendant-or-self::*[namespace-uri()='' and local-name()='" << localName << "']");
  }
  else if (namespaceURI->equals("*") == true)
  {
    if (localName->equals("*") == true)
      format = "descendant-or-self::*[node-type()=1]";
    else
      format = SBSTR("descendant-or-self::*[local-name()='" << localName << "']");
  }
  else
  {
    if (localName->equals("*") == true)
      format = "descendant-or-self::*[namespace-uri()='%s' and node-type()=1]";
    else
      format = SBSTR("descendant-or-self::*[namespace-uri()='" << namespaceURI << "' and local-name()='" << localName << "']");
  }

  xmlXPathContextPtr ctx = _createContextPathPtr(_nodePtr);
  xmlXPathObjectPtr eval = 0;
  if (ctx != 0)
  {
    eval = xmlXPathEval(STR2XML(format), ctx);
    xmlXPathFreeContext(ctx);
  }
  return new LibXMLPathNodeList(eval);
}

org::w3c::dom::RNodeList 
LibXMLElement::getElementsByTagNameNS(IN(RString) namespaceURI, IN(RString) localName)
{
  return _getElementsByTagNameNS(_nodePtr, namespaceURI, localName);
}
  
bool 
LibXMLElement::hasAttribute(IN(RString) name)
{
  return xmlGetProp(_nodePtr, STR2XML(name)) != 0;
}

bool 
LibXMLElement::hasAttributeNS(IN(RString) namespaceURI, IN(RString) localName)
{
  if (namespaceURI == Nil)
    return xmlGetNoNsProp(_nodePtr, STR2XML(localName)) != 0;
  else
    return xmlGetNsProp(_nodePtr, STR2XML(localName), STR2XML(namespaceURI)) != 0;
}

/*
### @todo implement me
RTypeInfo getSchemaTypeInfo()
{
  return new LibXMLTypeInfo(id);
}
*/

void 
LibXMLElement::setIdAttributeNode(IN(org::w3c::dom::RAttr) isAddr, bool isId)
{
  // ### @todo implement me
  THROW0(UnsupportedOperationException);
}

void 
LibXMLElement::setIdAttributeNS(IN(RString) namespaceURI, IN(RString) localName, bool isId)
{
  // ### @todo implement me
  THROW0(UnsupportedOperationException);
}

int 
LibXMLElement::attributeCount()
{
  xmlAttrPtr cur = _nodePtr->properties;
  int count = 0;
  while (cur != 0)
  {
    cur = cur->next;
    ++count;
  }
  return count;
}

org::w3c::dom::RAttr 
LibXMLElement::attribute(int idx)
{
  if (idx < 0)
    THROW2(DOMException, NOT_FOUND_ERR, SBSTR("LibXMLElement::attribute idx out of bounds. Index: " << idx));
  xmlAttrPtr cur = _nodePtr->properties;
  int count = 0;
  while (cur != 0)
  {
    if (count == idx)
      return (org::w3c::dom::RAttr)LibXMLNode::newInstance((xmlNodePtr) cur);
    cur = cur->next;
    ++count;
  }
  THROW2(DOMException, NOT_FOUND_ERR, SBSTR("LibXMLElement::attribute idx out of bounds. Index " << idx << ", attributeCount: " << count));
  return Nil;
}

int 
LibXMLPathNodeList::getLength()
{
  if (_xpathPtr == 0 || _xpathPtr->nodesetval == 0)
    return 0;
  return _xpathPtr->nodesetval->nodeNr;
}

org::w3c::dom::RNode 
LibXMLPathNodeList::item(int index)
{
  if (_xpathPtr == 0 || _xpathPtr->nodesetval == 0)
    return Nil;
  if (_xpathPtr->nodesetval->nodeNr <= 0)
    return Nil;
  return &LibXMLNode::newInstance(_xpathPtr->nodesetval->nodeTab[index]);
}

void 
LibXMLPathNodeList::_free()
{
  if (_xpathPtr != 0)
  {
    xmlXPathFreeObject(_xpathPtr);
    _xpathPtr = 0;
  }
}


} // namespace libxmldom
} // namespace xml
} // namespace acdk