From: <vac...@us...> - 2009-06-02 16:20:13
|
Revision: 149 http://xmlwrapp.svn.sourceforge.net/xmlwrapp/?rev=149&view=rev Author: vaclavslavik Date: 2009-06-02 16:20:11 +0000 (Tue, 02 Jun 2009) Log Message: ----------- Fixed xslt::stylesheet::apply() to detect and report errors. Modified Paths: -------------- trunk/NEWS trunk/include/xsltwrapp/stylesheet.h trunk/src/libxslt/init.cxx trunk/src/libxslt/stylesheet.cxx trunk/tests/xslt/test_xslt.cxx Added Paths: ----------- trunk/tests/xslt/data/with_errors.xsl Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2009-05-31 18:54:31 UTC (rev 148) +++ trunk/NEWS 2009-06-02 16:20:11 UTC (rev 149) @@ -5,6 +5,8 @@ Converted test suite to Boost Test. + Fixed xslt::stylesheet::apply() to detect and report errors. + Version 0.6.0 Fixed libxmlwrapp to not depend on libxslt if XSLT support Modified: trunk/include/xsltwrapp/stylesheet.h =================================================================== --- trunk/include/xsltwrapp/stylesheet.h 2009-05-31 18:54:31 UTC (rev 148) +++ trunk/include/xsltwrapp/stylesheet.h 2009-06-02 16:20:11 UTC (rev 149) @@ -58,6 +58,8 @@ class stylesheet { public: + struct pimpl; + /// Type for passing parameters to the stylesheet typedef std::map<std::string, std::string> param_type; @@ -160,7 +162,6 @@ const std::string& get_error_message() const; private: - struct pimpl; pimpl *pimpl_; // an xslt::stylesheet cannot yet be copied or assigned to. Modified: trunk/src/libxslt/init.cxx =================================================================== --- trunk/src/libxslt/init.cxx 2009-05-31 18:54:31 UTC (rev 148) +++ trunk/src/libxslt/init.cxx 2009-06-02 16:20:11 UTC (rev 149) @@ -49,7 +49,8 @@ extern "C" void xslt_error(void *, const char*, ...) { - // don't do anything + // don't do anything; we install context-specific error handler to + // catch errors while applying a stylesheet } } // anonymous namespace @@ -79,7 +80,8 @@ // set some defautls process_xincludes(true); - // keep libxslt silent + // keep libxslt silent; we install context-specific error handler to + // catch errors while applying a stylesheet xsltSetGenericErrorFunc(0, xslt_error); xsltSetGenericDebugFunc(0, xslt_error); Modified: trunk/src/libxslt/stylesheet.cxx =================================================================== --- trunk/src/libxslt/stylesheet.cxx 2009-05-31 18:54:31 UTC (rev 148) +++ trunk/src/libxslt/stylesheet.cxx 2009-06-02 16:20:11 UTC (rev 149) @@ -57,6 +57,17 @@ #include <vector> #include <map> + +struct xslt::stylesheet::pimpl +{ + pimpl (void) : ss_(0), errors_occured_(false) { } + + xsltStylesheetPtr ss_; + xml::document doc_; + std::string error_; + bool errors_occured_; +}; + namespace { @@ -110,35 +121,76 @@ } -xmlDocPtr apply_stylesheet(xsltStylesheetPtr s, xmlDocPtr d, +extern "C" void xsltwrapp_error_cb(void *c, const char *message, ...) +{ + xsltTransformContextPtr ctxt = static_cast<xsltTransformContextPtr>(c); + xslt::stylesheet::pimpl *impl = static_cast<xslt::stylesheet::pimpl*>(ctxt->_private); + + impl->errors_occured_ = true; + + // tell the processor to stop when it gets a chance: + if ( ctxt->state == XSLT_STATE_OK ) + ctxt->state = XSLT_STATE_STOPPED; + + // concatenate all error messages: + if ( impl->errors_occured_ ) + impl->error_.append("\n"); + + std::string formatted; + + va_list ap; + va_start(ap, message); + xml::impl::printf2string(formatted, message, ap); + va_end(ap); + + impl->error_.append(formatted); +} + + +xmlDocPtr apply_stylesheet(xslt::stylesheet::pimpl *impl, + xmlDocPtr doc, const xslt::stylesheet::param_type *p = NULL) { - /* - * TODO TODO TODO TODO - * - * use a transform context to capture error messages - * - * TODO TODO TODO TODO - */ + xsltStylesheetPtr style = impl->ss_; + std::vector<const char*> v; if (p) make_vector_param(v, *p); - return xsltApplyStylesheet(s, d, p ? &v[0] : 0); -} -} // end of anonymous namespace + xsltTransformContextPtr ctxt = xsltNewTransformContext(style, doc); + ctxt->_private = impl; + xsltSetTransformErrorFunc(ctxt, ctxt, xsltwrapp_error_cb); + // clear the error flag before applying the stylesheet + impl->errors_occured_ = false; -struct xslt::stylesheet::pimpl -{ - pimpl (void) : ss_(0) { } + xmlDocPtr result = + xsltApplyStylesheetUser(style, doc, p ? &v[0] : 0, NULL, NULL, ctxt); - xsltStylesheetPtr ss_; - xml::document doc_; - std::string error_; -}; + xsltFreeTransformContext(ctxt); + // it's possible there was an error that didn't prevent creation of some + // (incorrect) document + if ( result && impl->errors_occured_ ) + { + xmlFreeDoc(result); + return NULL; + } + if ( !result ) + { + // set generic error message if nothing more specific is known + if ( impl->error_.empty() ) + impl->error_ = "unknown XSLT transformation error"; + return NULL; + } + + return result; +} + +} // end of anonymous namespace + + xslt::stylesheet::stylesheet(const char *filename) { std::auto_ptr<pimpl> ap(pimpl_ = new pimpl); @@ -192,7 +244,7 @@ bool xslt::stylesheet::apply(const xml::document &doc, xml::document &result) { xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only()); - xmlDocPtr xmldoc = apply_stylesheet(pimpl_->ss_, input); + xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input); if (xmldoc) { @@ -208,7 +260,7 @@ const param_type &with_params) { xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only()); - xmlDocPtr xmldoc = apply_stylesheet(pimpl_->ss_, input, &with_params); + xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, &with_params); if (xmldoc) { @@ -223,14 +275,10 @@ xml::document& xslt::stylesheet::apply(const xml::document &doc) { xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only()); - xmlDocPtr xmldoc = apply_stylesheet(pimpl_->ss_, input); + xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input); - if (xmldoc == 0) - { - if (pimpl_->error_.empty()) - pimpl_->error_ = "unknown XSLT transformation error"; + if ( !xmldoc ) throw std::runtime_error(pimpl_->error_); - } pimpl_->doc_.set_doc_data_from_xslt(xmldoc, new result_impl(xmldoc, pimpl_->ss_)); return pimpl_->doc_; @@ -241,14 +289,10 @@ const param_type &with_params) { xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only()); - xmlDocPtr xmldoc = apply_stylesheet(pimpl_->ss_, input, &with_params); + xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, &with_params); - if (xmldoc == 0) - { - if (pimpl_->error_.empty()) - pimpl_->error_ = "unknown XSLT transformation error"; + if ( !xmldoc ) throw std::runtime_error(pimpl_->error_); - } pimpl_->doc_.set_doc_data_from_xslt(xmldoc, new result_impl(xmldoc, pimpl_->ss_)); return pimpl_->doc_; Added: trunk/tests/xslt/data/with_errors.xsl =================================================================== --- trunk/tests/xslt/data/with_errors.xsl (rev 0) +++ trunk/tests/xslt/data/with_errors.xsl 2009-06-02 16:20:11 UTC (rev 149) @@ -0,0 +1,19 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:output method="xml"/> + + <xsl:template name="foo"> + <output> + <xsl:value-of select="$x"/> + </output> + <!-- this is intentionally invalid: the parameters must be declared + at the top of the template --> + <xsl:param name="x"/> + </xsl:template> + + <xsl:template match="/"> + <xsl:call-template name="foo"> + <xsl:with-param name="x">42</xsl:with-param> + </xsl:call-template> + </xsl:template> + +</xsl:stylesheet> Modified: trunk/tests/xslt/test_xslt.cxx =================================================================== --- trunk/tests/xslt/test_xslt.cxx 2009-05-31 18:54:31 UTC (rev 148) +++ trunk/tests/xslt/test_xslt.cxx 2009-06-02 16:20:11 UTC (rev 149) @@ -131,4 +131,30 @@ } +/* + * Tests libxslt errors reporting + */ + +BOOST_AUTO_TEST_CASE( xsl_with_errors ) +{ + xslt::stylesheet style(test_file_path("xslt/data/with_errors.xsl").c_str()); + xml::tree_parser parser(test_file_path("xslt/data/input.xml").c_str()); + + xml::document result; + BOOST_CHECK( !style.apply(parser.get_document(), result) ); +} + +BOOST_AUTO_TEST_CASE( xsl_with_errors_throw ) +{ + xslt::stylesheet style(test_file_path("xslt/data/with_errors.xsl").c_str()); + xml::tree_parser parser(test_file_path("xslt/data/input.xml").c_str()); + + BOOST_CHECK_THROW + ( + style.apply(parser.get_document()), + std::exception + ); +} + + BOOST_AUTO_TEST_SUITE_END() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |