// 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;
}
|