/*************************************************************************** copyright : (C) 2003-2006 by Robby Stephenson email : robby@periapsis.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License as * * published by the Free Software Foundation; * * * ***************************************************************************/ #include "xslthandler.h" #include "../latin1literal.h" #include "../tellico_debug.h" #include "../tellico_utils.h" #include #include #include extern "C" { #include #include #include #include #include } // I don't want any network I/O at all static const int xml_options = XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOCDATA; static const int xslt_options = xml_options; /* some functions to pass to the XSLT libs */ static int writeToTQString(void* context, const char* buffer, int len) { TQString* t = static_cast(context); *t += TQString::fromUtf8(buffer, len); return len; } static void closeTQString(void* context) { TQString* t = static_cast(context); *t += TQString::fromLatin1("\n"); } using Tellico::XSLTHandler; XSLTHandler::XMLOutputBuffer::XMLOutputBuffer() : m_res(TQString()) { m_buf = xmlOutputBufferCreateIO((xmlOutputWriteCallback)writeToTQString, (xmlOutputCloseCallback)closeTQString, &m_res, 0); if(m_buf) { m_buf->written = 0; } else { myDebug() << "XMLOutputBuffer::XMLOutputBuffer() - error writing output buffer!" << endl; } } XSLTHandler::XMLOutputBuffer::~XMLOutputBuffer() { if(m_buf) { xmlOutputBufferClose(m_buf); //also flushes m_buf = 0; } } int XSLTHandler::s_initCount = 0; XSLTHandler::XSLTHandler(const TQCString& xsltFile_) : m_stylesheet(0), m_docIn(0), m_docOut(0) { init(); TQString file = KURL::encode_string(TQString::fromLocal8Bit(xsltFile_)); if(!file.isEmpty()) { xmlDocPtr xsltDoc = xmlReadFile(file.utf8(), NULL, xslt_options); m_stylesheet = xsltParseStylesheetDoc(xsltDoc); if(!m_stylesheet) { myDebug() << "XSLTHandler::applyStylesheet() - null stylesheet pointer for " << xsltFile_ << endl; } } } XSLTHandler::XSLTHandler(const KURL& xsltURL_) : m_stylesheet(0), m_docIn(0), m_docOut(0) { init(); if(xsltURL_.isValid() && xsltURL_.isLocalFile()) { xmlDocPtr xsltDoc = xmlReadFile(xsltURL_.encodedPathAndQuery().utf8(), NULL, xslt_options); m_stylesheet = xsltParseStylesheetDoc(xsltDoc); if(!m_stylesheet) { myDebug() << "XSLTHandler::applyStylesheet() - null stylesheet pointer for " << xsltURL_.path() << endl; } } } XSLTHandler::XSLTHandler(const TQDomDocument& xsltDoc_, const TQCString& xsltFile_, bool translate_) : m_stylesheet(0), m_docIn(0), m_docOut(0) { init(); TQString file = KURL::encode_string(TQString::fromLocal8Bit(xsltFile_)); if(!xsltDoc_.isNull() && !file.isEmpty()) { setXSLTDoc(xsltDoc_, file.utf8(), translate_); } } XSLTHandler::~XSLTHandler() { if(m_stylesheet) { xsltFreeStylesheet(m_stylesheet); } if(m_docIn) { xmlFreeDoc(m_docIn); } if(m_docOut) { xmlFreeDoc(m_docOut); } --s_initCount; if(s_initCount == 0) { xsltUnregisterExtModule(EXSLT_STRINGS_NAMESPACE); xsltUnregisterExtModule(EXSLT_DYNAMIC_NAMESPACE); xsltCleanupGlobals(); xmlCleanupParser(); } } void XSLTHandler::init() { if(s_initCount == 0) { xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 0; // register all exslt extensions exsltRegisterAll(); } ++s_initCount; m_params.clear(); } void XSLTHandler::setXSLTDoc(const TQDomDocument& dom_, const TQCString& xsltFile_, bool translate_) { bool utf8 = true; // XML defaults to utf-8 // need to find out if utf-8 or not const TQDomNodeList childs = dom_.childNodes(); for(uint j = 0; j < childs.count(); ++j) { if(childs.item(j).isProcessingInstruction()) { TQDomProcessingInstruction pi = childs.item(j).toProcessingInstruction(); if(pi.data().lower().contains(TQString::fromLatin1("encoding"))) { if(!pi.data().lower().contains(TQString::fromLatin1("utf-8"))) { utf8 = false; // } else { // myDebug() << "XSLTHandler::setXSLTDoc() - PI = " << pi.data() << endl; } break; } } } TQString s; if(translate_) { s = Tellico::i18nReplace(dom_.toString(0 /* indent */)); } else { s = dom_.toString(); } xmlDocPtr xsltDoc; if(utf8) { xsltDoc = xmlReadDoc(reinterpret_cast(s.utf8().data()), xsltFile_.data(), NULL, xslt_options); } else { xsltDoc = xmlReadDoc(reinterpret_cast(s.local8Bit().data()), xsltFile_.data(), NULL, xslt_options); } if(m_stylesheet) { xsltFreeStylesheet(m_stylesheet); } m_stylesheet = xsltParseStylesheetDoc(xsltDoc); if(!m_stylesheet) { myDebug() << "XSLTHandler::applyStylesheet() - null stylesheet pointer for " << xsltFile_ << endl; } // xmlFreeDoc(xsltDoc); // this causes a crash for some reason } void XSLTHandler::addStringParam(const TQCString& name_, const TQCString& value_) { TQCString value = value_; value.replace('\'', "'"); addParam(name_, TQCString("'") + value + TQCString("'")); } void XSLTHandler::addParam(const TQCString& name_, const TQCString& value_) { m_params.insert(name_, value_); // myDebug() << "XSLTHandler::addParam() - " << name_ << ":" << value_ << endl; } void XSLTHandler::removeParam(const TQCString& name_) { m_params.remove(name_); } const TQCString& XSLTHandler::param(const TQCString& name_) { return m_params[name_]; } TQString XSLTHandler::applyStylesheet(const TQString& text_) { if(!m_stylesheet) { myDebug() << "XSLTHandler::applyStylesheet() - null stylesheet pointer!" << endl; return TQString(); } m_docIn = xmlReadDoc(reinterpret_cast(text_.utf8().data()), NULL, NULL, xml_options); return process(); } TQString XSLTHandler::process() { if(!m_docIn) { myDebug() << "XSLTHandler::process() - error parsing input string!" << endl; return TQString(); } TQMemArray params(2*m_params.count() + 1); params[0] = NULL; TQMap::ConstIterator it = m_params.constBegin(); TQMap::ConstIterator end = m_params.constEnd(); for(uint i = 0; it != end; ++it) { params[i ] = qstrdup(it.key()); params[i+1] = qstrdup(it.data()); params[i+2] = NULL; i += 2; } // returns NULL on error m_docOut = xsltApplyStylesheet(m_stylesheet, m_docIn, params.data()); for(uint i = 0; i < 2*m_params.count(); ++i) { delete[] params[i]; } if(!m_docOut) { myDebug() << "XSLTHandler::applyStylesheet() - error applying stylesheet!" << endl; return TQString(); } XMLOutputBuffer output; if(output.isValid()) { int num_bytes = xsltSaveResultTo(output.buffer(), m_docOut, m_stylesheet); if(num_bytes == -1) { myDebug() << "XSLTHandler::applyStylesheet() - error saving output buffer!" << endl; } } return output.result(); } //static TQDomDocument& XSLTHandler::setLocaleEncoding(TQDomDocument& dom_) { const TQDomNodeList childs = dom_.documentElement().childNodes(); for(unsigned j = 0; j < childs.count(); ++j) { if(childs.item(j).isElement() && childs.item(j).nodeName() == Latin1Literal("xsl:output")) { TQDomElement e = childs.item(j).toElement(); const TQString encoding = TQString::fromLatin1(TQTextCodec::codecForLocale()->name()); e.setAttribute(TQString::fromLatin1("encoding"), encoding); break; } } return dom_; }