2005/5/9

     
 

NodeUtil.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 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/dom/NodeUtil.cpp,v 1.5 2005/02/05 10:45:36 kommer Exp $
#include <acdk.h>
#include <acdk/lang/Character.h>
#include <org/w3c/dom/Document.h>

#include "NodeUtil.h"
#include "NodeArrayList.h"
#include "XMLElement.h"
#include "XMLText.h"

namespace acdk {
namespace xml {
namespace dom {

using namespace org::w3c::dom;

String::iterator nextXPathToken(String::iterator it, String::iterator end)
{
  if (*it == '/')
    return it;

  while (it < end && Character::isLetterOrDigit(*it) == true)
  {
    ++it;
  }
  //if (it != end)
  //  --it;
  return it;
}


RNodeList 
NodeUtil::selectNodes(IN(RNode) node, IN(RString) xpath)
{
  String::iterator it = xpath->begin();
  String::iterator end = xpath->end();
  String::iterator newend = nextXPathToken(it, end);
  if (*it == '/')
  {
    RNode r = &node->getOwnerDocument();//->getDocumentElement();
    return selectNodes(r, xpath->substr(1));
  }
  else 
  {
    RString s = xpath->substr(0, newend - it);
    
    if (node->hasChildNodes() == false)
      return Nil;
    RNodeList nl = node->getChildNodes();
    int nll = nl->getLength();
    RNodeArrayList nodeList;
    if (newend == end)
      nodeList = new NodeArrayList();
    
    if (s->equals("text") && newend != end && *newend == '(' && *(newend + 1) == ')')
    {
      nodeList = new NodeArrayList();
      for (int i = 0; i < nll; ++i)
      {
        RNode sn = nl->item(i);
        if (instanceof(sn, Text) == true)
        {
          RXMLText t = (RXMLText)sn;
          nodeList->append(sn);
        }
      }
      return &nodeList;
    }
    else
    {
      for (int i = 0; i < nll; ++i)
      {
        RNode sn = nl->item(i);
        RString snn = sn->getNodeName();
        if (snn->equals(s) == true)
        {
          if (newend == end)
            nodeList->append(sn);
          else
            return selectNodes(sn, xpath->substr(newend - it + 1));
        }
      }
    }
    return &nodeList;
  }
}

org::w3c::dom::RNode 
NodeUtil::selectNode(IN(org::w3c::dom::RNode) node, IN(RString) xpath)
{
  RNodeList nl = selectNodes(node, xpath);
  if (nl == Nil || nl->getLength() == 0)
    return Nil;
  return nl->item(0);
}

void 
printNode(StringBuffer& sb, IN(RNode) node, IN(RString) ident);

void printSubNodes(StringBuffer& sb, IN(RNode) node, IN(RString) ident)
{
   RNodeList nl = node->getChildNodes();
  for (int i = 0; i < nl->getLength(); ++i)
  {
    printNode(sb, nl->item(i), ident + " ");
  }
}

void 
printNode(StringBuffer& sb, IN(RNode) node, IN(RString) ident)
{
  if (instanceof(node, Document) == true)
  {
     sb << "<?xml version=\"1.0\"?>\n";
     printSubNodes(sb, node, ident);
     return;
  }
  else if (instanceof(node, Element) == true)
  {
    RElement el = (RElement)node;
    RString tagname = el->getTagName();
    sb << ident << "<" << tagname;
    //RAttrArray attrs = el->getAttribues();
    for (int i = 0; i < el->attributeCount(); ++i)
    {
      RAttr att = el->attribute(i);
      sb << " " << att->getName() << "=\"" << att->getValue() << "\""; // ### @todo encode attr
    }
    if (el->hasChildNodes() == false)
    {
      RString val = el->getNodeValue();
      if (val == Nil || val->length() == 0)
      {
        sb << "/>\n";
        return;
      }
      sb << ">" << val << "</" << tagname << ">\n";
      return;
    }
    bool withIdent = true;
    if (instanceof(node->getChildNodes()->item(0), Text) == true)
      withIdent = false;
    if (withIdent == false)
      sb << ">";
    else
      sb << ">\n";
    
    printSubNodes(sb, node, ident);
    if (withIdent == true)
      sb << ident;
    sb << "</" << tagname << ">\n";
    return;
  }
  else if (instanceof(node, Text) == true)
  {
    RText t = (RText)node;
    sb << t->getData();
    return;
  }
}

//static 
RString 
NodeUtil::toXml(IN(org::w3c::dom::RNode) node)
{
  StringBuffer sb;
  printNode(sb, node, "");
  return sb.toString();
}

} // namespace dom
} // namespace xml
} // namespace acdk