IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

Make the most of Xerces-C++, Part 2

A DOM implementation

developerWorks

Return to article.


Listing 17. Code to produce SVG from source XML
        // svg.cpp
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/impl/DOMWriterImpl.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <iostream>
#include <xercesc/sax/SAXException.hpp>
#include <xercesc/dom/DOMWriter.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <stdio.h>
#include <stdlib.h>
#include "XercesString.h"
static XMLCh *value(XMLCh wszBuf[], unsigned uVal)
{
  char szLocal[32] = {0};
  sprintf(szLocal, "%u", uVal);
  XMLString::transcode(szLocal, wszBuf, 32);
  return wszBuf;
}
static bool getvalue(DOMElement &department, const XMLCh *strAttr, long *pnValue)
{
  bool bFound = false;
  DOMNode *pCursor = department.getFirstChild();
  while (pCursor != NULL && !bFound)
  {
    // is this a <department> element?
    if ( pCursor->getNodeType() == DOMNode::ELEMENT_NODE &&
		!XMLString::compareString(pCursor->getNodeName(), XercesString("figures") )  )
    {
      DOMElement *pFigure = (DOMElement*)pCursor;
      const XMLCh *strType = pFigure->getAttribute( XercesString("type") );
      bFound = !XMLString::compareString(strType, strAttr);
      if (bFound)
      {
        const XMLCh *strValue = pFigure->getAttribute( XercesString("value") );
		char *strTmp = XMLString::transcode(strValue);
		*pnValue = strtol(strTmp, NULL, 0);
      }
    }
    pCursor = pCursor->getNextSibling();
  }
  return bFound;
}
static bool getrange(DOMDocument &doc, const XMLCh *strAttr, long *pnMin, long *pnMax)
{
  long nMin = 0L, nMax = 0L;
  bool bOnce = false;
  DOMElement* pCorporate = doc.getDocumentElement();
  DOMNode* pCursor = pCorporate->getFirstChild();
  while (pCursor != NULL)
  {
    // is this a <department> element?
    if ( pCursor->getNodeType() == DOMNode::ELEMENT_NODE &&
      !XMLString::compareString(pCursor->getNodeName(), XercesString("department") ) )
    {
      long nValue = 0L;
      DOMElement* pDepartment = (DOMElement *)pCursor;
      if ( getvalue(*pDepartment, strAttr, &nValue) )
      {
        if (bOnce)
        {
          if (nMin > nValue) nMin = nValue;
          if (nMax < nValue) nMax = nValue;
        }
        else nMin = nMax = nValue;
        bOnce = true;
      }
    }
    pCursor = pCursor->getNextSibling();
  }
  *pnMax = nMax;
  *pnMin = nMin;
  return bOnce;
}
// transforms input corporate XML data to SVG viewable XML output data.
static bool dom2svg(DOMDocument &doc, const XMLCh *strAttr, DOMDocument **ppSVG)
{
  static const char *strColors[] =
    {"red", "blue", "yellow", "violet", "orange", "green"};
  const unsigned kLimit = sizeof strColors / sizeof strColors[0];
  unsigned uColor = 0; // use as a color index
  long nMin = 0L, nMax = 0L, nRange = 0L;
  DOMDocument *pSVG = NULL;
  if ( !getrange(doc, strAttr, &nMin, &nMax) )
    return false;
  nRange = nMax - nMin;
  // these next three lines of code create our output object,
  // set it's doctype, and create the root document element.
  DOMImplementation *pImpl = DOMImplementation::getImplementation();
  DOMDocumentType* pDoctype = pImpl->createDocumentType( XercesString("svg"), NULL, XercesString("svg-20000303-stylable.dtd") );
  pSVG = pImpl->createDocument(XercesString("svg"), XercesString("svg"), pDoctype);
  if (pSVG != NULL)
  {
    // output related nodes are prefixed with "svg" 
    // to distinguish them from input nodes.
	pSVG->setEncoding( XercesString("UTF-8") );
    DOMElement *pSvgRoot = pSVG->getDocumentElement();
    // sneak in the XML declaration just ahead of the doctype.
    //pSVG->insertBefore(svgDecl, pSVG->getDoctype() );
    // locate the XML root <corporate> element
    DOMElement* pCorporate = doc.getDocumentElement();
    // did we locate the root element?
    if (pCorporate != NULL)
    {
      XMLCh wszBuf[32] = {0};
      unsigned uX = 20, uY = 20;
      // yes: walk through the list of department elements beneath it.
      DOMNode* pCursor = pCorporate->getFirstChild();
      while (pCursor != NULL)
      {
        // is this a <department> element?
        if (  pCursor->getNodeType() == DOMNode::ELEMENT_NODE &&
          !XMLString::compareString(pCursor->getNodeName(), XercesString("department") )  )
        {
          XercesString wstrStyle("stroke:node; fill:");
          DOMElement* pDepartment = (DOMElement *)pCursor;
          long nValue = 0L;
          if ( getvalue(*pDepartment, strAttr, &nValue) )
          {
            // yes: create an SVG branch for this department
            DOMElement* pSvgG = pSVG->createElement( XercesString("g") );
            pSvgRoot->setAttribute( XercesString("width"), value(wszBuf, 320) );
            pSvgRoot->setAttribute( XercesString("height"), value(wszBuf, 200) );
            pSvgRoot->appendChild(pSvgG);
            // this <g> element will hold any SVG attributes (like font size 
            // and color) to be shared among the elements for this department.
            DOMElement* pSvgRect = pSVG->createElement( XercesString("rect") );
            pSvgG->appendChild(pSvgRect);
            pSvgG->setAttribute( XercesString("style"), XercesString("font-size:14") );
            // fill in the <rect> attributes
            wstrStyle.append( XercesString(strColors[uColor++ % kLimit]) );
            pSvgRect->setAttribute( XercesString("style"), wstrStyle );
            pSvgRect->setAttribute( XercesString("x"), value(wszBuf, uX+80) );
            pSvgRect->setAttribute( XercesString("y"), value(wszBuf, uY) );
            if (!nRange) nValue = 0;
            else nValue = 80 * (nValue - nMin) / nRange;
            nValue += 20;
            pSvgRect->setAttribute( XercesString("width"), value(wszBuf, nValue) );
            pSvgRect->setAttribute( XercesString("height"), value(wszBuf, 20) );
            DOMElement* pSvgText = pSVG->createElement( XercesString("text") );
            pSvgG->appendChild(pSvgText);
            DOMText* pSvgName = pSVG->createTextNode( pDepartment->getAttribute( XercesString("name") ) );
            pSvgText->setAttribute( XercesString("x"), value(wszBuf, uX) );
            pSvgText->setAttribute( XercesString("y"), value(wszBuf, uY+15) );
            pSvgText->appendChild(pSvgName);
            uY += 20;
          }
        }
        pCursor = pCursor->getNextSibling();
      }
      DOMElement* pSvgText = pSVG->createElement( XercesString("text") );
      pSvgText->setAttribute( XercesString("x"), value(wszBuf, uX) );
      pSvgText->setAttribute( XercesString("y"), value(wszBuf, uY+15) );
      DOMText* pSvgDisclaimer = pSVG->createTextNode( XercesString("Reported figures are preliminary only.") );
      pSvgText->appendChild(pSvgDisclaimer);
      pSvgText->setAttribute( XercesString("style"), XercesString("font-size:10") );
      pSvgRoot->appendChild(pSvgText);
    }
  }
  *ppSVG = pSVG;
  return true;
}
// Tries to return an XML DOM document 
// object for a given file name.
static bool doc2dom(const XMLCh *src, DOMDocument** ppDoc)
{
  bool bSuccess = false;
  //DOMString strMessage;
  XercesDOMParser *parser = new XercesDOMParser;
  if (parser)
  {
	char *strSrc = XMLString::transcode(src);
    parser->setValidationScheme(XercesDOMParser::Val_Auto);
    parser->setDoNamespaces(false);
    parser->setDoSchema(false);
    parser->setCreateEntityReferenceNodes(false);
    //parser->setToCreateXMLDeclTypeNode(true);
    try
    {
	  LocalFileInputSource source(src);
      bSuccess = false;
      parser->parse(source);
      bSuccess = parser->getErrorCount() == 0;
      if (!bSuccess)
      {
        std::cerr << "Parsing " << strSrc;
        std::cerr << " error count: " << parser->getErrorCount() << std::endl;
      }
    }
    catch (const DOMException& e)
    {
      std::cerr << "DOM Exception parsing ";
      std::cerr << strSrc;
      std::cerr << " reports: ";
	  // was message provided?
	  if (e.msg)
	  {
		// yes: display it as ascii.
		char *strMsg = XMLString::transcode(e.msg);
        std::cerr << strMsg << std::endl;
		XMLString::release(&strMsg);
	  }
	  else
	    // no: just display the error code.
        std::cerr << e.code << std::endl;
    }
    catch (const XMLException& e)
    {
      std::cerr << "XML Exception parsing ";
      std::cerr << strSrc;
      std::cerr << " reports: ";
      std::cerr << e.getMessage() << std::endl;
    }
    catch (const SAXException& e)
    {
      std::cerr << "SAX Exception parsing ";
      std::cerr << strSrc;
      std::cerr << " reports: ";
      std::cerr << e.getMessage() << std::endl;
    }
    catch (...)
    {
      std::cerr << "An exception parsing ";
      std::cerr << strSrc << std::endl;
    }
    // did the input document parse okay?
    if (bSuccess)
      *ppDoc = parser->getDocument();
	XMLString::release(&strSrc);
  }
  return bSuccess;
}
// appends the suggested file extension to the 
// file path if it does not already have one.
static void massage(XercesString &wstrPath, const XMLCh *strTail, bool bChop = false)
{
  bool bTail = false;
  int nDex = wstrPath.size();
  while (!bTail && nDex--)
  {
    const XMLCh ch = wstrPath[nDex];
    switch (ch)
    {
      case L'.':
        bTail = true;
        break;
	  case L'/':
	  case L'\\':
        break;
      default:
        break;
	}
  }
  if (!bTail)
  {
    wstrPath.append(strTail);
  }
  else if (bChop)
  {
	wstrPath.erase(wstrPath.begin() + nDex, wstrPath.end());
    wstrPath.append(strTail);
  }
}
int main(int argc, char* argv[])
{
  char *src = NULL, *dst = NULL;
  if (argc == 2)
  {
    dst = src = argv[1];
  }
  else if (argc == 3)
  {
    src = argv[1];
    dst = argv[2];
  }
  // initialize library
  XMLPlatformUtils::Initialize();
  if (src && dst)
  {
    DOMDocument* pDoc = NULL;
	XercesString wstrSrc(src), wstrDst(dst);
    // massage parameters into file names with proper extension.
    massage(wstrSrc, XercesString(".xml") );
    massage(wstrDst, XercesString(".svg"), true);
    // attempt to parse the document into a DOM object.
    if ( doc2dom(wstrSrc, &pDoc) )
    {
      DOMDocument* pSvg = NULL;
	  DOMWriterImpl writer;
	  LocalFileFormatTarget fileTarget(wstrDst);
	  //StdOutFormatTarget coutTarget;
      if ( pDoc->hasChildNodes() )
      {
        // parsed okay convert input DOM object
        // into an SVG output DOM object.
        dom2svg(*pDoc, XercesString("sales"), &pSvg);
        // write the resulting document.
		writer.setEncoding( XercesString("UTF-8") );
		writer.writeNode(&fileTarget, *pSvg);
		//writer.writeNode(&coutTarget, *pSvg);
      }
      else 
        std::cerr << "empty document!\n";
    }
    else
      std::cerr << "Opening & parsing document " << src << " fails!";
  }
  else
  {
    // throw the user a clue.
    std::cerr << "Usage:\n";
    std::cerr << "xml2svg <in-file> <out-file>\n";
    std::cerr << " -- or --\n";
    std::cerr << "xml2svg <in-file>\n";
  }
  // cleanup library
  getchar();
  XMLPlatformUtils::Terminate();
  return 0;
}
      

Return to article.

    关于 IBM 隐私条约 联系 IBM 使用条款